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

时间:2011-07-12 03:10:29

标签: javascript ajax

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

假设在异步调用myFunction时,我的页面上调用了一些名为myCallback的JavaScript方法。

一项操作优先于另一项操作吗?它们都同时运行吗?会发生什么?

8 个答案:

答案 0 :(得分:56)

  

假设在异步调用myFunction时,我的页面上调用了一些名为myCallback的JavaScript方法。

     

一项操作优先于另一项操作吗?它们都同时运行吗?会发生什么?

浏览器上的JavaScript是单线程的(禁止使用web workers,其语法是明确的)。所以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();

由于浏览器上的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();

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

您还可以以非显而易见的方式屈服于主机环境。例如,通过调用alert或其呼吸confirmprompt等,这些功能就像现代JavaScript中的疼痛拇指一样突出,因为它们不是事件驱动;相反,在显示模态窗口时暂停JavaScript执行。但正如bobincehis in-depth discussion here指出的那样,这并不意味着当该模式显示时,您的其他代码都不会运行。它仍然是单线程的,但是一个线程被暂停在一个地方(通过模态)并且在此期间用于在其他地方运行代码;确实非常好的区别。 (Bob还指出了一些事件处理 - 他的focus示例 - 似乎违反了这条规则,但事实并非如此。他的示例调用 focus,后者又调用事件处理程序,然后返回;与你调用自己的函数没什么不同。)Bob指出的项目的关键在于你的代码在宿主环境中调用了某些内容并且做了某些事情(显示模式对话框,触发blurfocus处理程序等。)

alert及其呼吸特别引起各种各样的肮脏,特别是在focusblur附近,我建议避免它们采用更现代的技术(也可以看大约18倍更好)。)

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

答案 1 :(得分:7)

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

编辑:Upvoting Joe的回答链接到Is JavaScript guaranteed to be single-threaded?并提及微妙的边缘案例。非常有用。

答案 2 :(得分:3)

Javascript类型的单线程请参阅Is JavaScript guaranteed to be single-threaded?。所以答案是否定的,您的事件处理程序和您的函数可以同时运行,或者它们可能不运行。

答案 3 :(得分:2)

AJAX回调在下一个事件循环上运行。

答案 4 :(得分:0)

ajax同时调用。因此,当ajax调用成功时,将调用回调函数,然后调用myfunction。

答案 5 :(得分:0)

您可以通过发出警报('第一个')来快速测试;警报('第二个');在这两个函数中,看看哪个模态弹出窗口首先出现。如果您的代码确实受到订单的影响,请在两者中进行一些条件检查以防止/允许某些操作。原生js的速度与进出服务器的完整往返速度完全不同。除非你有一些javascript在无限循环中运行,否则在你的其他函数执行期间返回的ajax调用的几率很小。

答案 6 :(得分:0)

AJAX呼叫是“异步”,这意味着“发起呼叫并让我知道你希望我在完成后回电话”。

简而言之:

function DoSomething() { AJAXCall(Callback); }

 ... some time passes then ...

function Callback() { Done(); }

在这两个函数调用之间可能发生任何事情,当响应返回时仍会调用回调,因为虽然javascript运行时是单线程的,但浏览器会以某种顺序堆栈调用(可能是它们的顺序)但不保证。)

很遗憾,我刚刚完成了我的旧网站,因为我有一个经典的例子,一个页面在加载时进行了几次ajax调用,因为每次调用都会回来,它会填充页面的各个部分。

尽管每个调用都“附加”到文档加载事件,但一次只能进行1次调用,但服务器可以按任何顺序响应任何调用,因为服务器可能是多线程的(可能是)。

将javascript视为一个虚拟框,浏览器可以在其中传递一小块代码,它一次只能运行1个块,但它可以按照它认为合适的顺序运行大量脚本(通常这是多个ajax调用无法预测,因为谁知道服务器什么时候可能会返回结果)

答案 7 :(得分:-1)

当ajax成功并调用myCallback时,它将同步运行。所以myCallback就像其他函数一样,你先调用它先运行它,或者你最后调用它最后运行它。他们不会在同一时间跑。