MessageChannel 消息通道

Posted Wise.Wrong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MessageChannel 消息通道相关的知识,希望对你有一定的参考价值。

一、初识 MessageChannel 对象

通过构造函数 MessageChannel() 可以创建一个消息通道,实例化的对象会继承两个属性:port1port2

port1 和 port2 都是 MessagePort 对象,在这里是只读的,无法对其进行字面量赋值

不过可以给 port 添加属性

上图还体现了 MessagePort 对象具有 onmessageonmessageerror 两个属性

这是两个回调方法,使用 MessagePort.postMessage 方法发送消息的时候,就会触发另一个端口的 onmessage

 

消息通道就像是一条左右贯通的管道,左右两个端口就是 port1 和 port2

这两个端口可以相互发送消息,port1 发送的消息可以在 port2 接收到,反之亦然

 

 

二、多个 Web Worker 之间通信

MessageChannel 可以结合 Web Worker 实现多线程通信

// main.js

let worker1 = new Worker(\'./worker1.js\');
let worker2 = new Worker(\'./worker2.js\');
let ms = new MessageChannel();

// 把 port1 分配给 worker1 worker1.postMessage(
\'main\', [ms.port1]);
// 把 port2 分配给 worker2 worker2.postMessage(
\'main\', [ms.port2]); worker2.onmessage = function(event) { console.log(event.data); }

这里的 postMessage() 可以接收两个参数:message、transferList

message 消息内容,可以是任意基础数据类型
transferList 由被传输对象组成的数组,这些对象的所有权会转移给调用 postMessage 的对象

 

 

 

所以上面的代码,就是把消息通道的 port1 分配给了 worker1,把 port2 分配给 worker2

也就是用消息通道,将两个 worker 给连接起来

// worker1.js
onmessage = function(e) {
    if (e.data === \'main\') {
        const port = e.ports[0];
        port.postMessage(\'Hi! I\'m worker1\');
    }       
}
// worker2.js
onmessage = function(e) {
    if (e.data === \'main\') {
        const port = e.ports[0];
        port.onmessage = function(e) {
            postMessage(e.data);
        }
    }
}

代码运行的时候,worker1 中通过 port1 发送消息,然后 worker2 就能从 port2 中接收到消息

 

三、深拷贝

大部分需要深拷贝的场景,都可以使用以下代码:

JSON.parse(JSON.stringify(object))

但这种办法会忽略 undefined、function、symbol循环引用的对象

而通过 postMessage() 方法传输的 message 参数是深拷贝的

所以可以借用 MessageChannel 实现深拷贝:

// 深拷贝函数
function deepClone(val) {
  return new Promise(resolve => {
    const { port1, port2 } = new MessageChannel()
    port2.onmessage = e => resolve(e.data)
    port1.postMessage(val)
  })
}

// 定义一个包含 undefined 的对象
let obj = {
  a: \'wise\',
  b: undefined,
  c: {
    d: \'wrong\'
  }
}
// 循环引用
obj.c.e = obj.c

// 注意该方法是异步的
async function test() {
  const clone = await deepClone(obj)
  console.log(clone)
}
test()

但这个深拷贝只能解决 undefined循环引用对象的问题,对于 Symbolfunction 依然束手无策

 

 

参考资料:

《HTML5 postMessage iframe跨域web通信简介》

《MessageChannel是什么,怎么使用?》

以上是关于MessageChannel 消息通道的主要内容,如果未能解决你的问题,请参考以下文章

教你如何实现页面间的数据通信

SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介创建消息生产者创建消息消费者自定义消息通道分组与持久化设置 RoutingKey)(代码片段

MessageChannel 和 WebSockets 的区别?

MessageChannel是什么,怎么使用?

没有带有拉动刷新的互联网消息 webview 片段

#yyds干货盘点# springcloud整合stream实现同一通道根据消息内容分发不同的消费逻辑