有可能“错过”吗?如果你在请求触发后订阅了JS中的异步事件

Is it possible to "miss" an async event in JS if you subscribe for it after you've asked for its triggering?

本文关键字:JS 事件 异步 错过 如果 请求 有可能      更新时间:2023-09-26

下面是一个简单的Ajax请求代码

var req = new XMLHttpRequest();
req.open('GET', 'http://www.mozilla.org/', true);
req.send(null); // First - send the request
// Then bind for the "result"
req.onreadystatechange = function (e) {
    if (req.readyState == 4 && req.status == 200) {
        // ...
    }
};

我在这里做什么:

  1. 发送Ajax请求。
  2. 然后绑定结果回调。

如果你认为这段代码是多线程的——很明显,你可以在请求完成后绑定到onreadystatechage(由于调度),它将永远不会被调用。

但是在基于反应器的代码中,这将始终按照预期工作,因为反应器直到我的所有代码完成该迭代的运行之后才会运行。

在浏览器中是哪种情况?这在什么地方有记录吗?

忽略Ajax请求是一个缓慢的事情,这可能永远不会在实践中发生的事实。我只是把它作为一个异步的例子(想想websocket,如果ajax对你来说太慢了)。

在这个意义上,JavaScript不是多线程的。在你说了。send(null)之后,你将完成当前代码块的执行,其中包括onreadystatechange,只有这样事件才会被触发。您的代码不会因为事件触发而在这两句话之间中断—事件将被添加到事件队列中(如果您愿意,可以缓冲),并且当有时间时,事件将触发,调用与之相关的所有处理程序。它应该调用在创建XMLHttpRequest对象和触发事件之间添加的处理程序。

至少,这是我对这个问题的解释。有关更多信息,请访问Javascript中的定时和同步,在dev.opera.

理论上不,事件处理程序的触发应该发生在事件队列上,因此必须在当前时间片完成后的时间片中发生,这意味着req.onreadystatechange = ...发生在任何事件被处理之前。参见javascript -事件驱动和并发问题?来理解JavaScript的并发模型(至少在浏览器中)。

在实践中,Firefox过去有(可能仍然有)一个bug,特别是onreadystatechange事件与用于发送请求的XMLHttpRequest对象的帧的事件队列同时触发。我养成了让我的onreadystatechange处理程序做setTimeout(0, ...)的习惯,以确保我没有在Firefox上得到讨厌的交错。

如果你在new otherWindow.XMLHttpRequest(...)中使用XMLHttpRequest对象跨帧,这也是可能的,因为在当前时间片(在此帧的事件队列中)完成之前,响应可以在另一帧的事件队列上处理。

是否有可能"错过"一个异步事件在JS如果你订阅它后,你已经要求它的触发?

不,这是不可能的- 如果在事件发生之前绑定处理程序。

事件发生无论如何。当它发生时,将调用此时注册的所有处理程序。

理论上是可能的。

为了避免它,将req.onreadystatechange = ...放在req.send(null);之前。