window.MessageChannel也是浏览器提供的一个异步操作的API,属于宏任务。
MessageChannel的应用场景
消息通道就像是一条左右贯通的管道,左右两个端口就是 port1 和 port2,这两个端口可以相互发送消息,port1 发送的消息可以在 port2 接收到,反之亦然。

1.多个 Web Worker之间通信
worker1.js和worker2.js
// worker1.js
onmessage = function(e) {
if (e.data === 'main') {
const port = e.ports[0];
port.postMessage("Hi! I am worker1 ");
}
}
// worker2.js
onmessage = function(e) {
if (e.data === 'main') {
const port = e.ports[0];
port.onmessage = function(e) {
postMessage(e.data);
}
}
}
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 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);
}
</script>
</body>
</html>
运行效果:

2.实现深拷贝
大部分需要深拷贝的场景,通常使用JSON.parse(JSON.stringify(object))。但这种办法会忽略 undefined、function、symbol 和循环引用的对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>循环引用的深拷贝问题</h1>
<hr>
<script>
function deepClone(obj) {
return new Promise((resolve, reject) => {
try {
const {port1, port2} = new MessageChannel();
port1.postMessage(obj);
port2.onmessage = msg => {
const cloneObj = msg.data;
//console.log(cloneObj);
resolve(cloneObj);
}
} catch (err) {
reject(err);
}
})
}
let p = {
name: '张三丰',
age: 68,
address: '湖北武当山'
}
p.person = p; //出现循环引用。
//console.log(p);
//JSON.stringify无法解决循环引用问题。
//let obj = JSON.parse(JSON.stringify(p));
deepClone(p).then(resp => {
console.log(resp)
})
</script>
</body>
</html>
运行效果:

注意:
使用 MessageChannel 实现的深拷贝只能解决 undefined和循环引用对象的问题,对于 Symbol 和 function 依然束手无策。