关于 postMessage

postMessage API可以用来解决跨域页面通信的问题。因此,当初决定使用postMessage解决书城和阅读器的通信问题。但是在使用过程中,还是有了波折。按照MDN的文档,书城通过window.open打开阅读器,同时通过readerReferer(阅读器页面句柄)发送信息。阅读器则监听message事件,获取数据。

// 代码大致如下
// 书城
const url = 'xxx'
const readerReferer = window.open(url)
readerReferer.postMessage({
  dest: 'reader',
  name: 'bookName'
}, url)
// 阅读器
window.addEventListener('message', handleMessage)
function handleMessage (e) {
  if (e.data.dest === 'reader') {
    console.log(e)
  }
}

运行时发现,虽然成功打开了阅读器页面(不成功也难~~),但是阅读器页面始终没有接收到postMessage的信息。网上关于这方面的资料也不多。但好歹找到一个靠谱的说法:postMessage只管发送信息,但对方有没有接收到则不管。

原因找到了,阅读器从打开到监听事件是需要时间的,而书城的信息在此之前就发出了。

网上也提供了解决方法:发送方不立即发送信息,而是等待接收方告知可以发送了再发送信息。

// 修改后的大致代码
// 书城
const url = 'xxx'
const readerReferer = window.open(url)
window.addEventListener('message', canISend)
function canISend(e) {
  if (e.data.from === 'reader') {
    readerReferer.postMessage({
      dest: 'reader',
      name: 'bookName'
    }, url)
  }
}
// 阅读器
window.addEventListener('message', handleMessage)
function handleMessage (e) {
  if (e.data.dest === 'reader') {
    console.log(e)
  }
}
window.opener.postMessage({
  from: 'reader'
}, '*')