如果您在要求触发后订阅它,是否有可能“错过”JS中的异步事件?

时间:2011-08-07 14:04:48

标签: javascript ajax browser asynchronous websocket

这是一个简单的剪辑来执行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. 然后绑定结果回调。
  3. 如果您认为此代码为多线程 - 很明显您可以在请求完成后绑定到onreadystatechage(由于调度),并且永远不会调用它。

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

    浏览器的情况如何?这是在某处记录的吗?

    忽略Ajax请求很慢的事实,这在实践中可能永远不会发生。我只是将它作为异步示例(如果ajax对你来说太慢,请考虑websocket)。

4 个答案:

答案 0 :(得分:2)

理论上没有,事件处理程序的触发应该发生在事件队列上,因此必须在当前时间片完成后的时间片中发生,这意味着{{1在处理任何事件之前发生。请参阅javascript - event driven and concurrency issues?以了解JavaScript的并发模型(至少在浏览器中)。

实际上,Firefox曾经(可能还有)一个错误,其中特别是req.onreadystatechange = ...事件与使用onreadystatechange对象发送请求的帧的事件队列同时触发。我养成了让XMLHttpRequest处理程序执行onreadystatechange的习惯,以确保我在Firefox上没有令人讨厌的交错。

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

答案 1 :(得分:2)

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

至少,这是我对这个问题的解释。有关详细信息,请访问dev.opera上的Timing and synchronization in Javascript

答案 2 :(得分:1)

  

如果您在请求触发后订阅它,是否有可能“错过”JS中的异步事件?

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

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

答案 3 :(得分:1)

理论上它是可能的。

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