Channel Messaging与structured clone

才疏学浅,以前没听过structured clone(结构化克隆)这个词语,最近才看到。

Channel Messaging API ,允许附着在同一个文档上的两个运行在不同上下文的脚本直接通信。

window下的postMessage

postMessage这个东西以前也用过,比如下面这个demo所示的用法:

我用的webstorm

index.html嵌套一个iframe,在index.html中的js代码如下:

window.addEventListener('message',function(e){
        console.log('message,',e.data)
},false);

在iframe中的js如下:

window.parent.postMessage('来自iframe的呼唤', 'http://localhost:63342/');

index.html的控制台会输出:

message, 来自iframe的呼唤

web worker与postMessage

demo的逻辑是父页面传递给worker一个数据,worker修改之后在返回。
父页面:

let worker = new Worker('worker.js');
let obj = [[0], [1]];
worker.postMessage(obj);
worker.addEventListener('message', function (data) {
    console.log('传递给worker的数据为', JSON.stringify(obj));
    console.log('从worker传过来的数据为:', JSON.stringify(data.data));
});

worker.js:

self.addEventListener('message', function (data) {
    console.log('从父页面传过来的数据:', JSON.stringify(data.data));
    data.data[2] = [2];
    console.log('传递给父页面的数据为:', JSON.stringify(data.data));
    postMessage(data.data);
});

跑一下,输出为:

从父页面传过来的数据: [[0],[1]]
传递给父页面的数据为: [[0],[1],[2]]
传递给worker的数据为 [[0],[1]]
从worker传过来的数据为: [[0],[1],[2]]

奇诡了吧,父页面传递给worker的是一个包含数组的数组,并且在worker中做了修改,但是父页面中的obj居然没发生变化。这个就是结构化克隆。

The structured clone algorithm is an algorithm defined by the HTML5 specification for copying complex JavaScript objects. It is used internally when transferring data to and from Workers via postMessage() or when storing objects with IndexedDB.

用这个东西就能实现深度克隆了吧!

MessageChannel实现深度克隆

在页面中实现深度克隆的时候总不能专门开个worker吧。
这是第一次接触MessageChannel。
MessageChannel 有两个只读的属性,port1和port2。

The port1 …… originated the channel….

The port2 …… the other end of the channel, which the message is initially sent to.

我试了一下,两个可以互换。
深度克隆,实现如下:

function structuralClone(obj) {
    return new Promise(resolve => {
        const {port1, port2} = new MessageChannel();//对象的解构赋值
        port2.onmessage = ev => resolve(ev.data);
        port1.postMessage(obj);//port.postMessage(message, transferList);,第二个参数可选
    });
}

const obj = [1, [2, 3]];
structuralClone(obj).then(e => {
    obj[1] = [4, 5];
    console.log(`原数组修改过后:`, JSON.stringify(obj));
    console.log(`复制后的数组:`, JSON.stringify(e));
});

上面的代码基本是照抄的参考文献3,但是有修改,原本的报错,因为await
这个深度克隆不可以克隆Error对象, Function对象, symbols, DOM节点。

好几个postMessage,有点乱了,整理一下他们的参数,表格如下:

postMessage第一个参数第二个参数第三个参数
port.postMessagemessagetransferList ,可选
worker.postMessagemessagetransferList,可选
targetWindow.postMessagemessagetargetOrigintransfer,可选

参考文献:
1. https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
2. https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
3. https://dassur.ma/things/deep-copy/
4. https://developer.mozilla.org/en-US/docs/Web/API/Worker
5. https://juejin.im/entry/5adfe5476fb9a07a9d6ffe16

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值