HTML5 API 多端通信桥 MessageChannel 技术

这篇具有很好参考价值的文章主要介绍了HTML5 API 多端通信桥 MessageChannel 技术。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这个特别有意思,可以将其理解为通信桥的概念,桥有两个端(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出现之前,你可能需要这样做:

  1. Worker A向主线程发送一个消息。

  2. 主线程接收到这个消息后,再将它转发给Worker B。

  3. Worker B接收到这个消息后,再向主线程发送一个回复。

  4. 主线程接收到这个回复后,再将它转发给Worker A。

这种方式需要主线程作为中介,进行大量的消息转发,这可能会增加主线程的负担,降低应用程序的性能。

而有了MessageChannel之后,你可以直接在两个Web Workers之间创建一个通信通道,然后这两个Web Workers就可以直接通信,无需通过主线程。这样可以减少主线程的负担,提高应用程序的性能。

此外,MessageChannel还支持传输Transferable对象,这可以避免数据的复制,进一步提高性能。而在MessageChannel出现之前,如果你想在不同的上下文之间传输大量的数据,你可能需要进行昂贵的数据复制或者序列化和反序列化操作。

总的来说,MessageChannel提供了一种更简单、更直接、更高效的跨上下文通信方式。

HTML5 中案例代码

https://github.com/mdn/dom-examples/tree/main/channel-messaging-basic

下面是我根据 ChatGPT 探索的两个 iframe 的双向通信代码,记住 iframe 和 webview 一样,在没将页面 load 完成时,你发过去的消息,嵌入页面收不到,这个在测试时是不报错的,很恶心!

index.html
<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width" />
    <title>Channel messaging demo</title>
  </head>
  <body>
    <h1>Channel messaging demo</h1>
    <p class="output">My body</p>
    <iframe id="iframe1" src="page1.html" width="480" height="320"></iframe>
    <iframe id="iframe2" src="page2.html" width="480" height="320"></iframe>
    <script>
      const iframe1 = document.getElementById('iframe1');
      const iframe2 = document.getElementById('iframe2');

      const channel = new MessageChannel();

      iframe1.onload = () => {
        iframe1.contentWindow.postMessage('port', '*', [channel.port1]);
      }

      iframe2.onload = () => {
        iframe2.contentWindow.postMessage('port', '*', [channel.port2]);
      }

    </script>
  </body>
</html>

Page1.html

<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width"/>
    <title>My page title</title>
    <STYLE>
        body {
            background-color: antiquewhite;
        }

        .output {
            color: #747070;
        }
    </STYLE>
</head>
<body>
<p class="output">iFrame body</p>
<script>
    const output = document.querySelector(".output");

    window.onmessage = (event) => {
        const port = event.ports[0];
        console.log(`Page1初始拿到的数据${event.data}`);

        port.onmessage = (e) => {
            // console.log('来自iframe2的消息:', e.data);
            output.innerHTML = e.data;
        };

        port.postMessage('Hello, iframe2!');
        let timer = 1;
        setInterval(() => {
            port.postMessage(`这是来自iframe1第${timer}消息`);
            timer++;
        }, 2000)
    };
</script>
</body>
</html>

Page2.html

<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width"/>
    <title>My page title</title>
</head>
<body>
<p class="output">iFrame body</p>
<script>
    const output = document.querySelector(".output");

    window.onmessage = (event) => {
        const port = event.ports[0];
        console.log(`Page2初始拿到的数据${event.data}`);

        port.onmessage = (e) => {
            // console.log('来自iframe1的消息:', e.data);
            output.innerHTML = e.data;
        };

        port.postMessage('Hello, iframe1!');
        let timer = 1;
        setInterval(() => {
            port.postMessage(`这是来自iframe2第${timer}消息`);
            timer++;
        }, 1000)
    };
</script>
</body>
</html>

三者之间的实现效果

HTML5 API 多端通信桥 MessageChannel 技术,Javascript,html5,前端,html

补充知识

postMessage 的三个参数分别有什么作用?

window.postMessage(message, targetOrigin, [transfer])

targetOrigin参数是一个字符串,表示消息的目标源(协议+主机+端口)。你可以使用这个参数来限制哪些窗口可以接收你的消息,以提高安全性。

以下是使用targetOrigin参数的示例:

htmlCopy code<!-- 父页面 -->
<iframe id="iframe" src="http://example.com/iframe.html"></iframe>

<script>
  const iframe = document.getElementById('iframe');

  iframe.onload = () => {
    // 只有当iframe的源是http://example.com时,它才能接收这个消息
    iframe.contentWindow.postMessage('Hello, world!', 'http://example.com');
  };
</script>

当 targetOrigin="*"时,则代表着向所有 iframe 进行广播的效果

window.onmessage 和 window.addEventListener('message', ...)两者之间的区别是什么?

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', ...)

 文章来源地址https://www.toymoban.com/news/detail-621801.html

到了这里,关于HTML5 API 多端通信桥 MessageChannel 技术的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包