【message-channel】了解频繁出现在框架的 Message Channel,及在事件循环(Event Loop)中的表现
介绍 Message Channel
使用
示例
const { port1, port2 } = new MessageChannel();
port1.onmessage = function (event) {
console.log('收到来自port2的消息:', event.data); // 收到来自port2的消息: pong
};
port2.onmessage = function (event) {
console.log('收到来自port1的消息:', event.data); // 收到来自port1的消息: ping
port2.postMessage('pong');
};
port1.postMessage('ping');
use addEventListener
const { port1, port2 } = new MessageChannel();
port1.addEventListener('message', function (event) {
console.log('收到来自port2的消息:', event.data); // 收到来自port2的消息: pong
});
port1.start();
port2.addEventListener('message', function (event) {
console.log('收到来自port1的消息:', event.data); // 收到来自port1的消息: ping
port2.postMessage('pong');
});
port2.start();
port1.postMessage('ping');
使用
EventListener
需要手动调用start()
后才可通信,因为初始化是暂停的。在使用onmessage
时隐式调用了start()
方法。
与 Iframe 通信
Main
const channel = new MessageChannel();
const { port1, port2 } = channel;
port1.onmessage = (event) => {
console.log(event.data, '----- port1 get message');
};
port2.onmessage = (event) => {
console.log(event.data, '------ port2 get message');
};
const iframe = document.querySelector('iframe');
iframe.addEventListener('load', () => {
iframe.contentWindow.postMessage('from main -- postMessage', '*', [port1]);
});
Iframe
window.addEventListener('message', (event) => {
const { data, ports } = event;
const [port1] = ports || [];
console.log(data, 'iframe get message', event);
});
互相通信
Iframe
+ let messagePort;
window.addEventListener('message', (event) => {
const { data, ports } = event;
const [port1] = ports || [];
console.log(data, 'iframe get message', event);
+ messagePort = port1;
});
+button.onclick = () => {
// message channel
+ messagePort?.postMessage('message from iframe')
+}
此处的
port1
是来自:iframe.contentWindow.postMessage('xxxx', '*', [port1]);
( postMessage 方法能够接受一个由 Transferable Objects 组成的数组作为参数,而 MessageChannel 导出的 MessagePort 刚好是 Transferable Objects )
Window.open
Main
let strWindowFeatures = 'top=10,left=10,width=400,height=200';
const newWindow = window.open(url, 'message', strWindowFeatures);
newWindow.addEventListener('load', () => {
newWindow.postMessage('message from new window', '*', [port1]);
});
new window
与 Iframe 逻辑大体一致
let messagePort;
window.addEventListener('message', (event) => {
const { data, ports } = event;
const [port1] = ports || [];
console.log(data, 'iframe get message', event);
messagePort = port1;
});
button.onclick = () => {
// message channel
messagePort?.postMessage('message from iframe');
};
Event Loop 中执行顺序
const interval = setInterval(() => {
console.log('setInterval');
window.clearInterval(interval);
});
setTimeout(() => {
console.log('timeout');
});
const { port1, port2 } = new MessageChannel();
port1.postMessage('send message');
port2.onmessage = () => {
console.log('get message');
};
requestAnimationFrame(() => console.log('requestAnimationFrame'));
new Promise((resolve) => {
console.log('promise');
resolve();
}).then(() => {
console.log('then');
});
async function A() {
console.log('A run');
await new Promise((resolve) => resolve());
console.log('A end');
}
A();
输出为
promise, A run
then, A end
requestAnimationFrame
timeout(先调先运行), get message, setInterval
https://segmentfault.com/a/1190000042501046
https://zhuanlan.zhihu.com/p/432726048
https://developer.mozilla.org/zh-CN/docs/Web/API/MessageChannel/MessageChannel
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 kshao-blog-前端知识记录!
评论