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>

三者之间的实现效果

补充知识

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/17652.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】图文并茂,通过逻辑图带你轻松拿捏链表,实现各种接口功能

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;我们接着之前讲过的顺序表来继续介绍初阶数据结构的内容&#xff0c;今天给大家带来的是有关链表的基本知识和各种接口功能的实现 好了&#xff0c;废话不多说&#x…

英语语法 名词和冠词 详解

目录 一、名词概述 1.基本介绍 : 2.作用 : (在句子中可担任的语法成分) 1 作主语 2 作宾语 3 作表语 4 作定语 5 作同位语 二、专有名词和普通名词 1.专有名词&#xff1a; 1 定义 2 示例 3 关于名词的大小写 2.普通名词&#xff1a; 1 定义 2 示例 3 分类 三、可数名词和不…

kubernetes错误汇总

title: “kubernetes错误汇总” categories: - “技术” tags: - “Kubernetes” - “错误汇总” toc: false original: true draft: false 1、增加 master etcd 报错 1.1、错误描述 由于创建的k8s集群&#xff0c;其中有一个master节点初始化失败&#xff0c;先删除了这个节…

LeetCode 周赛上分之旅 # 36 KMP 字符串匹配殊途同归

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

day50-Insect Catch Game(捉虫游戏)

50 天学习 50 个项目 - HTMLCSS and JavaScript day50-Insect Catch Game&#xff08;捉虫游戏&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport"…

codeblocks编译lvgl报错

codeblocks编译lvgl报错 1.报错内容2.解决方案3.lvgl本身代码报错 1.报错内容 error: unknown type name _In_opt_ ...2.解决方案 官网下载&#xff1a; 这里的Compiler’s installation directory 选择自带的 3.lvgl本身代码报错 undefined reference to _lv_utils_bse…

面试总结-Redis篇章(九)——Redis主从复制、主从数据同步原理

Redis其他面试问题 主从复制单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离主节点主要进行客户端的写操作&#xff0c;从节点进行客户端的读操作&#xff0c;因为Redis一直都是读多写少&…

UE5.1.1 创建C++项目失败

因一直使用Unity开发环境&#xff0c;安装Unreal后&#xff0c;并未详细配置过其开发环境&#xff0c;默认创建蓝图工程无异常&#xff0c;但创建UE C项目时总共遇到两个错误&#xff1a; 错误一 Running /Epic/UE/UE_5.1/Engine/Build/BatchFiles/Build.bat -projectfiles -…

flutter项目运行时一直卡在Running Gradle task ‘assembleDebug‘解决办法

1.修改项目中的android/build.gradle&#xff0c;将google()&#xff0c;mavenCentral()替换为下面的代码 maven { url https://maven.aliyun.com/repository/central/ }maven { url https://maven.aliyun.com/repository/public/ }maven { url https://maven.aliyun.com/repos…

<C++>二、类和对象-构造函数

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生…

【Linux多线程】死锁问题介绍

死锁 &#x1f96d;什么是死锁&#x1f965;死锁产生的条件&#x1f95d;如何避免死锁&#x1f345; 避免死锁算法 &#x1f96d;什么是死锁 死锁是多线程或多进程编程中的一种常见问题&#xff0c;指的是两个或多个线程&#xff08;或进程&#xff09;相互等待对方持有的资源&…

位操作相关的函数(C++)

目录 popcount函数 bitset类模板 __builtin_popcount函数 popcount函数 在C中&#xff0c;std::popcount函数是用来计算一个整数二进制表示中包含的1的个数。不过要注意&#xff0c;这个函数是C20标准引入的&#xff0c;因此在使用之前&#xff0c;要先确保编译器支持C20标…

Redis 理论部分

前面写了很多redis项目&#xff0c;今天在通过redis的理论加深redis的了解&#xff0c;顺便做个总结 Redis 理论部分 1.redis 速度快的原因 纯内存操作单线程操作&#xff0c;避免频繁的上下文切换以及资源争用的问题&#xff0c;多线程需要占用更多的cpu资源采用非阻塞I/O多…

搜索二叉树_SearchBinaryTree

目录 搜索二叉树的原理 搜索二叉树的搜索时间复杂度 二叉搜索树实现_key 模型 节点 构造函数 查找 中序遍历 插入 循环 递归 删除 循环 1.删除叶子节点 2.删除有一个孩子的节点 3.左右孩子都不为空 递归 析构函数 拷贝构造 operator key_value 模型 节点 …

Mysql触发器

1.触发器 触发器是与表有关的数据库对象&#xff0c;指在 insert / update / delete 之前或之后&#xff0c;触发并执行触发器中定义的SL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性&#xff0c;日志记录&#xff0c;数据校验等操作。 使用别名 OLD 和 …

C#常用数学插值法

目录 1、分段线性插值 2、三次样条插值 3、拉格朗日插值 &#xff08;1&#xff09;一元全区间不等距插值 &#xff08;2&#xff09;一元全区间等距插值 4、埃尔米特插值 &#xff08;1&#xff09;埃尔米特不等距插值 &#xff08;2&#xff09;埃尔米特等距插值 1、…

mysql安装教程保姆级

MySQL免安装本地运行 1.下载MySQL2.创建install.bat3.init.sql 初始创建4.环境变量配置5.运行 install.bat 管理员权限运行6.连接成功遇到的问题 1.下载MySQL ①地址&#xff1a;https://downloads.mysql.com/archives/community/ ②解压 2.创建install.bat 放在mysql>b…

【SpringBoot笔记37】SpringBoot基于@ServerEndpoint、@OnMessage等注解的方式集成WebSocket

这篇文章,主要介绍SpringBoot基于@ServerEndpoint、@OnMessage等注解的方式集成WebSocket。 目录 一、基于注解集成WebSocket 1.1、WebSocket常见注解 1.2、创建WebSocket服务端 1.3、配置ServerEndpointExpor

java数据算法-汉诺塔

1、有三根相邻的柱子&#xff0c;标号为A,B,C。 2、A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘。 3、现在把所有盘子一个一个移动到柱子C上&#xff0c;并且每次移动同一根柱子上都不能出现大盘子在小盘子上方。 题解步骤 1、当n1时&#xff1b; 将1号从A移动到C即…

算法综合篇专题一:双指针问题

"就算没有看清那株灿烂的花蕊&#xff0c;也应该放声歌颂赞美鲜红的玫瑰" 1、移动零 (1) 题目解析 (2) 算法原理 class Solution { public:void moveZeroes(vector<int>& nums) {for(int cur0,dest-1;cur<nums.size();cur){if(nums[cu…