几种postMessage

在初见postMessage的时候被其强大的功能震撼到了,可是自己用起来却总是莫名报错

原来是我把几种postMessage搞混了,现在来和我一起捋清楚吧

首先三种都是宏任务

BroadcastChannel.postMessage

适用于在同一域名下所有页面之间的广播通信

  1. 标签页间共享

通过BroadcastChannel构造函数生成的

1
2
const bc = new BroadcastChannel('channel_name')
bc.name // bcName

有两个实例方法:

  1. close()
  2. postMessage(message) 向同名频道广播(很像websocket)

事件:
onmessageaddEventListener('message',()=>{}) 之间没有区别

MessagPort.postMessage

常用在仅仅需要两个端口互相发送数据的场合
深拷贝

通过MessageChannel构造函数生成的实例channel,有两个实例属性他们都是 MessagePort的实例

1
2
const {port1, port2} = new MessageChannel()
console.dir(port1 instanceof MessagePort) // true

MessagePort有
实例方法:

  1. close() 关闭端口,会阻止端口接收和发送
  2. postMessage(message, [transfer]) 发送消息,transfer往下看
  3. start() 开始接收消息,往往配合如下方式使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    port1.postMessage('message from port1')
    //方法一:只有用addEventListener来监听message事件需要调用start
    port2.addEventListener('message', function (e) {
    console.log(e.data);
    })
    port2.start()
    //方法二:用onmessage,隐含调用了start
    port2.onmessage = function(e) {
    console.log(e.data)
    }

transfer Transferable对象

transfer 是一个可选的Transferable对象的数组
transfer将被转移而不是克隆到新的上下文中,这意味着它们在发送消息的上下文中不再可用
(可以打印,但是打印出来相当于是new contructor(), 它只剩一副空壳!)

注意:
我认为在MessagePort.postMessage中转移另一个port没有意义(浅浅的认知)

但是你可以转移一个buffer

1
2
3
4
5
6
7
8
9
10
const { port1, port2 } = new MessageChannel();
const buffer = new ArrayBuffer(8);
port1.postMessage(buffer, [buffer]);
(function(){
//另一个上下文
port2.onmessage = function(e) {
const receivedBuffer = e.data;
console.log(receivedBuffer)
};
})()

js 上下文

关于js中上下文的含义(点我)

window.postMessage

在不同window对象进行安全的跨源通信,例如当前winow和iframe.contentWindow之间

1
window.postMessage(message, targetOrigin, [transfer]);

targetOrigin: 通过window.origin与targetOrigin是否匹配,从而判断window能否接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个 URL

message事件:与上面两个不同,window的message事件是谁发送,谁注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <iframe src="./iframe.html">
</iframe>
<script>
const ifr = document.querySelector('iframe')
ifr.onload = function () {
ifr.contentWindow.postMessage('hello', "*")
}
</script>
<!-- 同目录下的iframe -->
<script>
window.addEventListener('message',function(e) {
console.log('iframe: ', e.data);
})
</script>

iframe 最好用src相对地址引入一个文件
<iframe> 标签中指定 src 属性,那么这个内容会异步加载。用js动态设置 src 属性,那么这个内容可能会同步加载