当脚本执行时AJAX调用返回时,JavaScript会发生什么?

Dan*_*don 38 javascript ajax

假设我编写了一些执行AJAX调用的JavaScript myCallback作为回调方法,以便在AJAX成功时执行.

假设myFunctionmyCallback异步调用时,我的页面上调用了一些其他调用的JavaScript方法.

一个操作优先于另一个操作吗?它们都同时运行吗?怎么了?

T.J*_*der 56

假设myFunctionmyCallback异步调用时,我的页面上调用了一些其他调用的JavaScript方法.

一个操作优先于另一个操作吗?它们都同时运行吗?怎么了?

浏览器上的JavaScript是单线程的(禁止使用Web工作者,其语法是明确的).所以myFunction一直运行直到它返回 - 有一些警告(继续阅读).如果ajax层在运行 完成一个操作myFunction(很可能),并且需要调用回调,那么该调用将排队.下次代码生成时,将触发队列中的下一个调用.

那么,我们似乎永远不必担心竞争条件.这基本上是正确的,但有微妙之处.例如,考虑以下代码:

var img = document.createElement('img');
img.src = /* ...the URL of the image... */;
img.onload = function() {
    // Handle the fact the image loaded
    foo();
};
doSomethingElse();
doYetAnotherThing();
Run Code Online (Sandbox Code Playgroud)

由于浏览器上的JavaScript是单线程的,因此我保证load在图像加载时获取事件,对吧?

错误.

的JavaScript代码是单线程的,但环境的其余部分可能不是.因此,它可以发生,将其具有的img.src,浏览器可能会看到它有它可以使用图像的缓存副本,所以它触发load事件对img 之间img.src = ...线路和img.onload = ...线路.由于我的处理程序尚未附加,我没有接到电话,因为当我附加处理程序时,事件已经被触发.

但是如果我们反转这些行,你可以看到排队的效果:

var img = document.createElement('img');
img.onload = function() {
    // Handle the fact the image loaded
    foo();
};
img.src = /* ...the URL of the image... */;
doSomethingElse();
doYetAnotherThing();
Run Code Online (Sandbox Code Playgroud)

现在我设置挂钩了这个事件src.如果事件img.src = ...在行和doSomethingElse行之间触发(因为浏览器在缓存中有图像),则对我的处理程序的回调会排队.doSomethingElsedoYetAnotherThing在我的处理程序之前运行.只有当控制权从我的代码中传出时,才会运行对我的处理程序的排队调用.JavaScript代码是单线程的,但环境不是.

您还可以以非显而易见的方式屈服于主机环境.例如,通过调用alert或它的呼吸confirm,prompt等等.这些功能像现代JavaScript中的疼痛拇指一样突出,因为它们不是事件驱动的; 相反,在显示模态窗口时暂停JavaScript执行.但正如bobince其深入讨论中指出的那样,并不意味着当模式显示时,你的其他代码都不会运行.它仍然是单线程的,但是一个线程被暂停在一个地方(通过模态)并用于在此期间的其他地方运行代码; 确实非常好的区别.(鲍勃还指出了一些事件处理 - 他的focus例子 - 似乎打破了这个规则,但它没有.他的示例调用 focus,它反过来调用事件处理程序,然后返回;与调用自己的函数没有什么不同. Bob指出的项目的关键在于,你的代码已经在宿主环境中调用了一些东西,它会消失并做某事(显示模态对话框,触发器blurfocus处理程序等).

(alert其特别原因breathren种种污秽的,特别是围绕focusblur,我建议避免他们赞成更现代的技术(也可看约18倍更好).)

所以这些是答案开头提到的警告.特别是,如果myFunction调用alert,至少在Firefox上,ajax完成回调alert(在大多数其他浏览器上不会)运行.如果您想要尝试在期间发生和不发生的事情alerts,这里是测试页面测试setTimeout和ajax; 你可以扩展测试以进一步发展.


nin*_*cko 7

这些答案都是错误的[编辑:发布此答案时至少有3-4个错误].XHR事件放在事件队列/池中.当单线程javascript线程不忙时,它将从事件池中获取下一个事件,并对它们进行操作.其中一个事件将是您的XHR"AJAX"请求,它将触发回调,然后执行.这就是所有没有中断的事件驱动系统的工作方式.

编辑:Upvoting Joe的答案链接到Is JavaScript保证是单线程的吗?并提到了微妙的边缘案例.非常翔实.