← 返回首页
Javascript基础教程(五十五)
发表时间:2022-12-28 16:29:41
MessageChannel

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 依然束手无策。