常见的 macro task 有 setTimeout
、MessageChannel
、postMessage
、setImmediate
。而常见的 micro task 有 MutationObsever
和 Promise.then
。
MessageChannel
Channel Messaging API的MessageChannel
接口允许我们创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据。
Note: 此特性在 Web Worker 中可用
iframe通信
//主页面
<iframe id="iframe1" src="./iframe1.html"></iframe>
<iframe id="iframe2" src="./iframe2.html"></iframe>
<script>
window.onload = function(){
var {port1,port2} = new MessageChannel();
var iframe1 = document.getElementById('iframe1');
iframe1.contentWindow.postMessage('main','*',[port1]);
var iframe2 = document.getElementById('iframe2');
iframe2.contentWindow.postMessage('main','*',[port2]);
}
</script>
//iframe1
<div id="message"></div>
<script>
window.addEventListener('message',function(event){
console.log(event);
let messageDom = document.getElementById('message');
messageDom.innerHTML = "收到" + event.origin + "消息:" + event.data;
let port = event.ports[0];
port.onmessage = function(e){
messageDom.innerHTML += '<br/>收到' + e.origin + '消息: ' + e.data;
}
port.postMessage('from iframe1');
}, false);
</script>
//iframe2
<div id="message"></div>
<script>
window.addEventListener('message',function(event){
console.log(event);
let messageDom = document.getElementById('message');
messageDom.innerHTML = "收到" + event.origin + "消息:" + event.data;
let port = event.ports[0];
port.onmessage = function(e){
messageDom.innerHTML += '<br/>收到' + e.origin + '消息: ' + e.data;
}
port.postMessage('from iframe2');
}, false);
</script>
Web Worker通信
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]);
//worker1.js
self.onmessage = function(e) {
console.log('worker1', e.ports);
if (e.data === 'main') {
const port = e.ports[0];
port.postMessage(`worker1: Hi! I'm worker1`);
port.onmessage = function(ev){
console.log('reveice: ',ev.data,ev.origin);
}
}
}
//worker2.js
self.onmessage = function(e) {
if (e.data === 'main') {
const port = e.ports[0];
port.onmessage = function(e) {
console.log('receive: ', e.data);
port.postMessage('worker2: ' + e.data);
}
}
}
BroadcastChannel
Broadcast Channel API 可以实现同 源 下浏览器不同窗口,Tab页,frame或者 iframe 下的 浏览器上下文 (通常是同一个网站下不同的页面)之间的简单通讯。
Note: 此特性在 Web Worker 中可用
广播频道会被命名和绑定到指定的源。
通过创建一个监听某个频道下的 BroadcastChannel 对象,你可以接收发送给该频道的所有消息。一个有意思的点是,你不需要再维护需要通信的 iframe 或 worker 的索引。它们可以通过构造 BroadcastChannel 来简单地“订阅”特定频道,并在它们之间进行全双工(双向)通信。
const bc1= new BroadcastChannel('channelA')
const bc2= new BroadcastChannel('channelB')
bc1.onmessage = (ev) => {
console.log(ev.data);
}
setTimeout(() => {
bc2.postMessage({message: 'hello'})
}, 1000)
setTimeout(() => {
bc1.close();
bc2.close();
}, 2000)