在使用BroadcastChannel API时,我意识到如果通道关闭,开发人员仍然尝试调用postMessage()
,则不会抛出任何异常;至少不是一直这样
第一个案例
close()
从与postMessage()
相同的broadcastChannel示例调用,抛出错误:
const bc1 = new BroadcastChannel('foo');
const bc2 = new BroadcastChannel('foo');
bc1.postMessage('bar');
bc2.addEventListener('message', (event) => console.log(event.data));
setTimeout(() => {
bc1.close(); // we're calling the close() from bc1, same instant where we will call postMessage later
}, 500);
setTimeout(() => {
try {
bc1.postMessage('bar2');
} catch (error) {
console.error('postMessage error', error);
}
}, 1000);
上面的代码会抛出一个异常:
postMessage error
Error: Failed to execute 'postMessage' on 'BroadcastChannel': Channel is closed
第二种情况
close()
是从另一个broadcastChannel示例调用的postMessage()
,不会抛出错误:
const bc1 = new BroadcastChannel('foo');
const bc2 = new BroadcastChannel('foo');
bc1.postMessage('bar');
bc2.addEventListener('message', (event) => console.log(event.data));
setTimeout(() => {
bc2.close(); // we're calling the close() from bc2, NOT the same instant where we will call postMessage later
}, 500);
setTimeout(() => {
try {
bc1.postMessage('bar2');
} catch (error) {
console.error('postMessage error', error);
}
}, 1000);
上面的代码没有抛出任何异常。在我看来,它应该抛出一个异常。
提问
在第二种情况下,是否有任何可能的方法来检测通道是否已经关闭?或者如果这是一个bug,我可以在哪里提交罚单?
如果你想玩MRE,这里是link。
1条答案
按热度按时间sczxawaw1#
在阅读了文档之后,我认为这是一个可以接受的行为。首先,这里有一个来自官方规范的注解:
强烈建议作者在不再需要BroadcastChannel对象时显式关闭它们,以便对它们进行垃圾回收。创建许多BroadcastChannel对象并丢弃它们,同时将它们保留在事件侦听器中,而不关闭它们,这可能会导致明显的内存泄漏,因为只要这些对象具有事件侦听器(或者直到它们的页面或worker被关闭),这些对象就会继续存在。
显然,我们需要清理BroadcastChannel示例以防止内存泄漏。现在,进一步思考,如果我们将消息广播到不同的上下文以同步/交换信息,我们需要在那里创建具有相同频道名称的示例。然而,其他情况可能很容易关闭,这导致为该特定情况清理资源。尽管如此,其他环境应该继续交换信息--表演必须继续。
总之,我认为不抛出异常是完全可以的,因为BroadCastChannel并不知道它的所有示例。为了解决这个问题,您可以创建一个close处理函数,它将被放置在每个BroadcastChannel侦听器中。例如:
然后你可以调用bChannel.postMessage('close');这将关闭所有示例(将关闭标志设置为假)。在此之后,他们应该抛出错误。