1、初識 MessageChannel 對象html
經過構造函數 MessageChannel() 能夠建立一個消息通道,實例化的對象會繼承兩個屬性:port1 和 port2html5
port1 和 port2 都是 MessagePort 對象,在這裏是只讀的,沒法對其進行字面量賦值web
不過能夠給 port 添加屬性跨域
上圖還體現了 MessagePort 對象具備 onmessage 和 onmessageerror 兩個屬性數組
這是兩個回調方法,使用 MessagePort.postMessage 方法發送消息的時候,就會觸發另外一個端口的 onmessage多線程
消息通道就像是一條左右貫通的管道,左右兩個端口就是 port1 和 port2異步
這兩個端口能夠相互發送消息,port1 發送的消息能夠在 port2 接收到,反之亦然async
2、多個 Web Worker 之間通訊wordpress
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 中接收到消息
3、深拷貝
大部分須要深拷貝的場景,均可以使用如下代碼:
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 和循環引用對象的問題,對於 Symbol 和 function 依然一籌莫展
參考資料: