zoukankan      html  css  js  c++  java
  • 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是什么,怎么使用?》

  • 相关阅读:
    PostgreSQL 安装和使用
    动态sql
    知识储备
    java空和非空判断
    我的第一篇博客
    正式工作:PreparedStatement 参与的
    mysql part2DML(数据操作语言)
    DCL(权限 ,用户)
    DQL(数据查询语言)
    准备工作:Eclipse 导入 mysql连接java 的jar包
  • 原文地址:https://www.cnblogs.com/wisewrong/p/10496531.html
Copyright © 2011-2022 走看看