概述
Channel Messaging API 的MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据。
继承自父类 EventTarget
方法
从端口发送一条消息,并且可选是否将对象的所有权交给其他浏览器上下文
开始发送该端口中的消息队列 (只有使用 EventTarget.addEventListener 的时候才需要调用;当使用 MessagePort.onmessage 时,是默认开始的。)
断开端口连接,它将不再是激活状态。
事件回调
是一个 EventListener, 当类型为
message的 MessageEvent 在该端口触发时,它将会被调用 ── 也就是说,该端口收到了一条消息。
是一个 EventListener, 当类型为
MessageError的 MessageEvent 被触发时,它将会被调用 ── 这意味着,端口收到了一条无法被反序列化的消息。
基本用法
const { port1, port2 } = new MessageChannel();
port1.onmessage = function (event) {
console.log('收到来自port2的消息:', event.data); // 收到来自port2的消息: pong
};
// port1.addEventListener('message', function (event) {
// console.log('收到来自port2的消息:', event.data); // 收到来自port2的消息: pong
// });
// port1.start();
port2.onmessage = function (event) {
console.log('收到来自port1的消息:', event.data); // 收到来自port1的消息: ping
port2.postMessage('pong');
};
port1.postMessage('ping');
- 注意:
addEventListener之后要手动调用start()方法消息才能流动,因为初始化的时候是暂停的。onmessage已经隐式调用了start()方法。
常用场景
用作深拷贝
function deepClone(obj) {
return new Promise((resolve, reject) => {
try {
const { port1, port2 } = new MessageChannel();
port2.onmessage = e => resolve(e.data);
port1.postMessage(obj);
} catch (e) {
reject(e);
}
});
}
const oldObj = { a: { b: 1 } };
deepClone(oldObj).then((newObj) => {
console.log(oldObj === newObj); // false
newObj.a.b = 2;
console.log(oldObj.a.b); // 1
}).catch(e => {
console.log(e); // 序列化错误
});
- 当消息包含
函数、Symbol等不可序列化的值时,就会报无法克隆的DOM异常
Web Worker(worker间通信)
// worker1.js
self.onmessage = function(e) {
const port = e.ports[0];
port.postMessage("this is from worker1")
}
// worker2.js
self.onmessage = function(e) {
const port = e.ports[0];
port.onmessage = function(e) {
self.postMessage(e.data)
}
}
// index.js
const worker1 = new Worker("worker1.js");
const worker2 = new Worker("worker2.js");
const channel = new MessageChannel();
worker1.postMessage("port1", [channel.port1]);
worker2.postMessage("port2", [channel.port2]);
worker2.onmessage = function(e) {
console.log(e.data);
}
iframe 和 页面之间通信
- 先使用 window.postMessage 建立 "连接"
- 之后的操作参考 worker间通信