一般 postMessage
用于不同页面窗口间通信,但在同一个页面内也是可以使用的。
window.addEventListener('message', e => {
if (
e.origin === location.origin &&
e.source === e.target &&
e.data === 'test'
) {
console.log(2)
}
})
出于安全考虑,判断是当前页面内(同一个页面同一个窗口)才执行相关逻辑:
e.origin === location.origin
同源e.source === e.target
同窗口
console.log(1)
window.postMessage('test', location.origin)
console.log(3)
postMessage
第二个参数是 targetOrigin
,消息也只发送给同源页面。
因为 postMessage
是宏任务,所以打印顺序是 1、3、2 。
那想按顺序打印 1、2、3 怎么办,中间加一个宏任务等待。
window.addEventListener('message', e => {
if (
e.origin === location.origin &&
e.source === e.target &&
e.data === 'test'
) {
console.log(2)
}
})
console.log(0)
window.postMessage('test', location.origin)
console.log(1)
await new Promise(r => setTimeout(r))
console.log(3)
await new Promise(r => setTimeout(r))
一行代码实现宏任务等待,setTimeout
也是宏任务,执行以上代码时,任务队列中 setTimeout
在 postMessage
后面,利用 await
和 Promise
实现等待。
另一种变体:postMessage
也可以放到 Promise
里,效果是一样的。
console.log(1)
await new Promise(r => {
window.postMessage('test', location.origin)
setTimeout(r)
})
console.log(3)
其实还可以有一种变体,既然 postMessage
是宏任务,那也可以不需要 setTimeout
,只通过 postMessage
来实现宏任务等待,因为是同一个窗口,可以借助 window 全局变量来搭个桥,存一下 Promise
的 resolve
,消息接收方在合适的时机执行这个回调。
window.addEventListener('message', e => {
if (
e.origin === location.origin &&
e.source === e.target &&
e.data === 'test'
) {
console.log(2)
if (typeof window.waitResolve === 'function') {
window.waitResolve() // Promise 的 resolve
delete window.waitResolve
}
}
})
console.log(1)
await new Promise(r => {
window.waitResolve = r
window.postMessage('test', location.origin)
})
console.log(3)
顺序打印 1、2、3
以上!