下面是一个简单的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) {
// ...
}
};
我在这里做什么:
- 发送Ajax请求。
- 然后绑定结果回调。
如果你认为这段代码是多线程的——很明显,你可以在请求完成后绑定到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);
之前。