双向 Javascript window.postMessage - 调度顺序问题

Joh*_*ohn 6 javascript xss iframe postmessage

postMessage 可用于在窗口之间发送消息,通常是从 iframe 到父级或从父级到 iframe。

postMessage 仅在一个方向上发送数据并且是外联的 - 不像函数调用,函数调用从调用返回值并内联执行(后者是前者的条件)。

为了将信息发送回“调用者”,“被调用者”必须自己做postMessage

现在让我们假设我想测试一个合适的监听器是否存在:我会postMessage根据一些约定,如果监听器存在,它会postMessage回来。

在什么时候我可以确定没有听众?我如何实现等待?

我在 IE11、Chrome 和 Firefox 上尝试了以下实验:

  1. postMessage 收到消息后立即回发的 iframe 窗口
  2. postMessage 自己的窗口作为在事件处理中调度未来点的一种手段

以下是这些步骤的代码:

var iframe = document.getElementById('iframe');
iframe.contentWindow.postMessage('hello', '*');
window.postMessage('schedule', '*')
Run Code Online (Sandbox Code Playgroud)

iframe 的响应代码是这样的:

window.addEventListener('message', function (event) {
    window.top.postMessage('echo ' + event.data, '*');
}, false);
Run Code Online (Sandbox Code Playgroud)

父窗口的侦听器本身是这样的:

var n = 0;
window.addEventListener("message", function (event) {
    if (n > 4) return;
    console.info(event.data);
    window.postMessage('(repeat of ' + event.data + ' #' + n + ')', '*')
    n++;
}, false);
Run Code Online (Sandbox Code Playgroud)

换句话说,我不断地重新调度事件,以便记录队列的性质。

在 IE11、Chrome 和 Firefox 上,这给出(反复):

schedule <-- shouldn't make the mistake to believe there's no listener yet!
echo hello
(repeat of schedule #0)
(repeat of echo hello #1)
(repeat of (repeat of schedule #0) #2)
Run Code Online (Sandbox Code Playgroud)

我可以“猜测”这是为什么:浏览器有一个消息队列,并将前两条消息(“hello”和“schedule”)放入。它们都将在稍后安排的任何消息之前处理。特别是,iframe 的应答将在处理“hello”消息时被调度,然后将在“schedule”消息之后进行处理。

因此,要确定是否有侦听器,必须在自己的窗口上发布“调度”消息,然后在该事件的处理过程中发布另一条“重复调度 #0”消息。

只有在处理这个间接的“repeat of schedule #0”消息时,仍然没有来自 iframe 的词,我们才能确定没有侦听器。

哇,对于这么简单的问题,这是一个复杂的解决方案。

我的问题是:是否有任何一种保证浏览器有一个公共消息队列,以便真正以这种方式调度事件?

当然,有没有更简单的方法仍然可靠?(甚至不要考虑计时器!)