3

假设我有一堆同源窗口或选项卡ABCDE,它们之间没有相互引用。(例如,用户独立打开它们)。假设A向其他人发送BroadcastChannel消息,因此D需要将一些数据发送A,理想情况下不涉及BCE

这是否可能,使用任何消息传递 API?

广播消息事件中有一个event.source属性,在这种情况下,它看起来好像应该包含一个WindowProxyMessagePort对象,但是(至少在我对 Firefox 78 的测试中)它只是null。还有一个ports数组,但那是空的。

...我知道您可以启动一个 SharedWorker 来为每个窗口分配一个唯一的 ID 并充当在它们之间传递消息的中转站,但是 (a) 对于所需的功能来说这似乎非常复杂,并且 (b) 每个以这种方式发送的消息将需要 2 次跃点,从窗口到 sharedWorker 再返回到窗口,两次都跨越线程边界,并且(通常)两次都被序列化和反序列化 - 即使两个窗口共享同一个 javascript 线程!所以效率不是很高。

这似乎是一件显而易见的事情,我发现很难相信我没有明显的遗漏......但我看不到它,如果是这样的话!

4

2 回答 2

2

看起来标准要求sourcea 为空BroadcastChannel。但它与其他几个使用 的 API共享MessageEventsource接口,因此它存在,但为空。

postMessage(message) 方法步骤是:
...
5. 从目标中删除源。

看起来他们故意保持BroadcastChannel非常轻巧。只是一个猜测,但您正在寻找的功能可能需要他们不想分配的额外资源。这个猜测是基于他们在规范中的一般说明:

对于复杂的情况,例如管理共享状态的锁定、管理服务器和多个本地客户端之间的资源同步、与远程主机共享 WebSocket 连接等等,共享工作者是最合适的解决方案。

但是,对于简单的情况,如果共享工作者的开销不合理,作者可以使用本节中描述的简单的基于频道的广播机制。

于 2020-07-28T23:40:21.400 回答
1

SharedWorkers 绝对更适合复杂的情况,将 BroadcastChannel 视为一对多的简单通知发送者。

它无法传输数据——那么哪个接收者应该成为所有者?— 因此,除了 Blob(它们只是没有自己的数据的小型包装器)的情况外,通过 BroadcastChannel 传递数据意味着它必须由所有接收器完全反序列化,而不是最高效的方式。

所以我不确定你需要发送什么样的数据,但如果它是通常应该可以传输的大数据,那么可能更喜欢 SharedWorker

但是,如果您的数据不被传输,一种解决方法是创建一个新的 BroadcastChannel,只有您的两个上下文会监听。

现场演示

在页面 A 中:

const common_channel = new BroadcastChannel( "main" );
const uuid = "private-" + Math.random();
common_channel.postMessage( {
  type: "gimme the data",
  from: "pageB",
  respondAt: uuid
} );
const private_channel = new BroadcastChannel( uuid );
private_channel.onmessage = ({data}) => {
  handleDataFromPageB(data);
  private_channel.close();
};

在 B 页

const common_channel = new BroadcastChannel( "main" );
common_channel.onmessage = ({ data }) => {
  if( data.from === "pageB" && data.type === "gimme the data" ) {
    const private_channel = new BroadcastChannel( data.respondAt );
    private_channel.postMessage( the_data );
    private_channel.close();
  }
};

关于为什么不能ports在 BroadcastChannels 上触发 MessageEvent 的值,这是因为 MessagePorts 必须被传输,但正如我们已经说过的,BroadcastChannels 不能进行传输。
为什么没有source,这可能是因为正如您所料,它应该是一个 WindowProxy 对象,但是 WorkerContexts 也可以将消息发布到 BroadcastChannels,并且它们没有实现该接口(例如,它们的postMessage方法根本不会做同样的事情而不是 WindowContext)。

于 2020-07-29T00:52:50.663 回答