这个特别有意思,可以将其理解为通信桥的概念,桥有两个端(port1,port2)只要将port1,port2指定到任意两个进程,无论是iframe-iframe,iframe-worker,parent-child-iframe,worker-worker等,只要搭好,两者就可以实时通信了。这解决了让parent作为中转站这种头大的问题,以下是该技术调研的细节。
相关链接:MessageChannel - Web API 接口参考 | MDN
在MessageChannel出现之前,跨上下文(例如,主线程、Web Workers、Service Workers或者不同的窗口或iframe)通信主要依赖于postMessage和onmessage事件。这种方式虽然有效,但在某些情况下可能会比较麻烦。
例如,假设你有一个主线程和两个Web Workers,你希望这两个Web Workers能够直接通信。在MessageChannel出现之前,你可能需要这样做:
Worker A向主线程发送一个消息。
主线程接收到这个消息后,再将它转发给Worker B。
Worker B接收到这个消息后,再向主线程发送一个回复。
主线程接收到这个回复后,再将它转发给Worker A。
这种方式需要主线程作为中介,进行大量的消息转发,这可能会增加主线程的负担,降低应用程序的性能。
而有了MessageChannel之后,你可以直接在两个Web Workers之间创建一个通信通道,然后这两个Web Workers就可以直接通信,无需通过主线程。这样可以减少主线程的负担,提高应用程序的性能。
此外,MessageChannel还支持传输Transferable对象,这可以避免数据的复制,进一步提高性能。而在MessageChannel出现之前,如果你想在不同的上下文之间传输大量的数据,你可能需要进行昂贵的数据复制或者序列化和反序列化操作。
总的来说,MessageChannel提供了一种更简单、更直接、更高效的跨上下文通信方式。
https://github.com/mdn/dom-examples/tree/main/channel-messaging-basic
下面是我根据 ChatGPT 探索的两个 iframe 的双向通信代码,记住 iframe 和 webview 一样,在没将页面 load 完成时,你发过去的消息,嵌入页面收不到,这个在测试时是不报错的,很恶心!
Channel messaging demo
Channel messaging demo
My body
Page1.html
My page title
iFrame body
Page2.html
My page title
iFrame body
window.postMessage(message, targetOrigin, [transfer])
targetOrigin参数是一个字符串,表示消息的目标源(协议+主机+端口)。你可以使用这个参数来限制哪些窗口可以接收你的消息,以提高安全性。
以下是使用targetOrigin参数的示例:
htmlCopy code
当 targetOrigin="*"时,则代表着向所有 iframe 进行广播的效果
window.onmessage和window.addEventListener('message', ...)都是用于监听message事件的方法,但它们的使用方式和行为有一些不同。
window.onmessage:这是一个事件处理属性,你可以将它设置为一个处理函数,这个函数会在message事件发生时被调用。如果你多次设置window.onmessage,那么后面的设置会覆盖前面的设置。也就是说,你只能有一个onmessage处理函数。
javascriptCopy codewindow.onmessage = (event) => {
console.log(event.data);
};
window.addEventListener('message', ...):这是一个方法,你可以用它来添加一个或多个message事件的监听器。如果你多次调用addEventListener,那么每次调用都会添加一个新的监听器,而不会覆盖旧的监听器。也就是说,你可以有多个message事件的监听器。
javascriptCopy codewindow.addEventListener('message', (event) => {
console.log(event.data);
});
总的来说,如果你只需要一个message事件的处理函数,你可以使用window.onmessage。如果你需要多个message事件的处理函数,或者你需要更复杂的事件处理(例如,使用捕获阶段,或者移除事件监听器),你可以使用window.addEventListener('message', ...)