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

时间:2021-11-19 01:26:09

Suppose I write some JavaScript that performs an AJAX call with myCallback as a callback method to execute when the AJAX succeeds.

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

Suppose then that some other JavaScript method called myFunction is being invoked on my page when myCallback is invoked asynchronously.

假设当异步调用myCallback时,我的页面上调用另一个名为myFunction的JavaScript方法。

Does one operation take precedence over the other? Do they both run at the same time? What happens?

一个操作优先于另一个操作吗?他们同时跑步吗?会发生什么呢?

8 个解决方案

#1


56  

Suppose then that some other JavaScript method called myFunction is being invoked on my page when myCallback is invoked asynchronously.

假设当异步调用myCallback时,我的页面上调用另一个名为myFunction的JavaScript方法。

Does one operation take precedence over the other? Do they both run at the same time? What happens?

一个操作优先于另一个操作吗?他们同时跑步吗?会发生什么呢?

JavaScript on browsers is single-threaded (barring your using web workers, and the syntax for that is explicit). So myFunction will run until it returns — with certain caveats (keep reading). If the ajax layer completes an operation while myFunction is running (which it very well may) and needs to invoke the callback, that call gets queued. The next time your code yields, the next call in the queue will be triggered.

浏览器上的JavaScript是单线程的(除非您使用web worker,而且其语法是显式的)。所以myFunction会一直运行直到它返回——有一些注意事项(继续阅读)。如果ajax层在myFunction运行时完成了一个操作(很可能是这样),并且需要调用回调,那么这个调用将被排队。下次代码生成时,将触发队列中的下一个调用。

It might seem, then, that we never have to worry about race conditions. That's mostly true, but there are subtleties. For instance, consider this code:

那么,我们似乎永远不必担心种族状况。这基本上是对的,但也有微妙之处。例如,考虑以下代码:

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

Since JavaScript on browsers is single-threaded, I'm guaranteed to get the load event when the image loads, right?

由于浏览器上的JavaScript是单线程的,所以我保证在图像加载时获得加载事件,对吗?

Wrong.

错了。

The JavaScript code is single-threaded, but the rest of the environment probably isn't. So it can happen that, having set the img.src, the browser may see that it has a cached copy of the image it can use, and so it triggers the load event on the img between the img.src = ... line and the img.onload = ... line. Since my handler isn't attached yet, I don't get the call, because by the time I've attached my handler, the event has already fired.

JavaScript代码是单线程的,但是环境的其他部分可能不是。设置img后,可能会发生这种情况。浏览器可能会看到它可以使用的映像的缓存副本,因此它触发img之间的img上的load事件。src =…线和img。onload =…线。由于我的处理程序还没有附加,所以我没有得到调用,因为当我附加我的处理程序时,事件已经触发。

But you can see the effect of queuing if we reverse those lines:

但是你可以看到排队的影响,如果我们颠倒这些线:

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

Now I'm hooking the event before setting src. If the event fires between the img.src = ... line and the doSomethingElse line (because the browser has the image in cache), the callback to my handler gets queued. doSomethingElse and doYetAnotherThing run before my handler does. Only when control passes out of my code does the queued call to my handler finally get run. The JavaScript code is single-threaded, but the environment is not.

现在我在设置src之前连接事件。如果事件在img之间触发。src =…line和doSomethingElse行(因为浏览器在缓存中有映像),我的处理程序的回调将进入队列。在我的处理器运行之前做一些其他的事情。只有当控件从代码中传出时,对我的处理程序的排队调用才会最终运行。JavaScript代码是单线程的,但是环境不是。

You can also yield to the host environment in non-obvious ways. For instance, by calling alert or its breathren confirm, prompt, etc. These functions stick out like the sore thumbs they are in modern JavaScript because they aren't event driven; instead, JavaScript execution is suspended while a modal window is shown. But as bobince points out in his in-depth discussion here, that doesn't mean none of your other code will run while that modal is showing. It's still single-threaded, but the one thread is being suspended in one place (by the modal) and used to run code elsewhere in the meantime; a very fine distinction indeed. (Bob also points to some event handling — his focus example — that seems to break this rule, but it doesn't. His example calls focus, which in turn calls the event handlers, and then returns; no different from you calling your own functions.) The key thing the items that Bob points out have in common is that your code has called into something in the host environment that does goes away and does something (shows a modal dialog, fires blur and focus handlers, etc.).

您还可以以不明显的方式屈服于宿主环境。例如,通过调用alert或它的breathren confirm、prompt等函数,这些函数就像现代JavaScript中的大拇指一样突出,因为它们不是事件驱动的;相反,在显示一个模态窗口时,JavaScript执行被挂起。但是正如bobince在他的深入讨论中指出的,这并不意味着在显示模式时,您的其他代码都不会运行。它仍然是单线程的,但是一个线程被挂起在一个地方(通过模式),同时用于在其他地方运行代码;这确实是一个非常细微的区别。(Bob还指出了一些事件处理——他的焦点例子——似乎打破了这条规则,但事实并非如此。他的示例调用focus,焦点反过来调用事件处理程序,然后返回;这和你调用自己的函数没什么不同。Bob指出的项目的关键之处在于,您的代码在主机环境中调用了一些东西,这些东西会消失并做一些事情(显示一个模态对话框,触发blur和焦点处理程序等)。

(alert and its breathren in particular cause all sorts of nastiness, particularly around focus and blur, and I recommend avoiding them in favor of more modern techniques (which can also look about 18x better).)

(特别的是,alert和它的呼吸系统会导致各种各样的不愉快,尤其是在焦点和模糊的周围,我建议避免使用它们,而采用更现代的技术(也可以更好地显示18倍)。)

So those are the caveats mentioned at the outset of the answer. And in particular, if myFunction calls alert, at least on Firefox the ajax completion callback will get run during the alert (it won't on most other browsers). If you're curious to try out what does and doesn't happen during alerts and such, here's a test page testing setTimeout and ajax; you could extend the tests to go further.

这些就是答案一开始提到的注意事项。特别是,如果myFunction调用alert,至少在Firefox上,ajax完成回调将在警报期间运行(在大多数其他浏览器上不会)。如果您想了解在警报期间发生了什么和没有发生什么,这里有一个测试页面,测试setTimeout和ajax;您可以进一步扩展测试。

#2


7  

These answers are all wrong [edit: at least 3-4 wrong when this answer was posted]. The XHR event is put in the event queue/pool. When the single-threaded javascript thread is not busy, it will grab the next events from the event pool, and act on them. One of those events will be your XHR "AJAX" request, which will trigger the callback, which will then execute. This is how all event-driven systems without interrupts work.

这些答案都是错误的。XHR事件放在事件队列/池中。当单线程javascript线程不繁忙时,它将从事件池中获取下一个事件,并对其进行操作。其中一个事件是XHR“AJAX”请求,它将触发回调,然后执行回调。这是所有事件驱动系统不中断工作的方式。

edit: Upvoting Joe's answer which links to Is JavaScript guaranteed to be single-threaded? and mentions the subtle edge-cases. Very informative.

编辑:向上投票乔的答案哪个链接是JavaScript保证是单线程的?并提到微妙的边缘情况。非常有益的。

#3


3  

Javascript kind of single threaded see Is JavaScript guaranteed to be single-threaded?. So the answer is NO, your event handler and your function could run at the same time, or they might not.

Javascript类型的单线程看到的Javascript保证是单线程的吗?所以答案是否定的,你的事件处理器和你的函数可以同时运行,或者它们不能同时运行。

#4


2  

The AJAX callback runs on the next event loop.

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

#5


0  

The ajax calls with be simultaneously. So when the ajax call is successful, the callback function is invoked which in turn invokes the the myfunction.

ajax调用同时进行。因此,当ajax调用成功时,将调用回调函数,该函数反过来调用myfunction。

#6


0  

You could quickly test this by putting an alert('first one'); alert('second one'); in both functions, and see which modal popup comes up first. If your code really is affected by the order, put some conditional checks in both to prevent / allow something. The speed of native js vs the speed of a full round-trip to and from the server is wildly different. Unless you have some javascript running in an infinite loop, the odds of the ajax call returning during your other function execution is tiny.

您可以通过设置一个警报(“第一个警报”)来快速测试这一点;alert('第二个');在这两个函数中,都可以看到哪个模式弹出窗口最先出现。如果您的代码确实受到顺序的影响,那么在两者中都进行一些条件检查,以防止/允许某些东西。本地js的速度与服务器往返的速度有天壤之别。除非在无限循环中运行一些javascript,否则在其他函数执行期间返回ajax调用的几率很小。

#7


0  

AJAX calls are "asyncronous" which means "fire off a call and let me know what you want me to call back when im done".

AJAX调用是“异步的”,意思是“启动一个调用,并让我知道您希望我在im完成时调用什么”。

so in short:

所以,简而言之:

function DoSomething() { AJAXCall(Callback); }

 ... some time passes then ...

function Callback() { Done(); }

Between those 2 function calls anything can happen, the callback will still be called when the response comes back because although the javascript runtime is single threaded the browser will stack calls to happen in some sort of order (likely the order they are made but not garanteed).

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

It's a shame i just pulled done my old website because i had classic example of a page making several ajax calls on load, as each call came back it would populate various portions of the page.

遗憾的是,我刚刚做了我的旧网站,因为我有一个经典的页面实例,它在加载时执行几个ajax调用,每次调用返回时都会填充页面的各个部分。

although each call was "attached" to the document loaded event only 1 call could be made at a time but the server could respond to any call in any order because the server could be multithreaded (and likely is).

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

Think of javascript as being a virtual box in which which the browser can pass a small lump of code, it can only run 1 lump at a time but it can run lots of scripts in whatever order it sees fit (generally this is unpredictable with multiple ajax calls because who knows when the server might come back with a result)

认为javascript是一个虚拟的盒子中,浏览器可以通过一小块代码,它只能运行1块一次,但它可以运行很多的脚本在它认为合适的(通常这与多个ajax调用是不可预测的,因为谁知道服务器什么时候会回来,结果)

#8


-1  

When the ajax succeeds and invokes myCallback, it will run synchronously. So myCallback is like other functions, you call it first it will run first or you call it last it will run last. THEY WILL NOT RUN AT THE SAME TIME.

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

#1


56  

Suppose then that some other JavaScript method called myFunction is being invoked on my page when myCallback is invoked asynchronously.

假设当异步调用myCallback时,我的页面上调用另一个名为myFunction的JavaScript方法。

Does one operation take precedence over the other? Do they both run at the same time? What happens?

一个操作优先于另一个操作吗?他们同时跑步吗?会发生什么呢?

JavaScript on browsers is single-threaded (barring your using web workers, and the syntax for that is explicit). So myFunction will run until it returns — with certain caveats (keep reading). If the ajax layer completes an operation while myFunction is running (which it very well may) and needs to invoke the callback, that call gets queued. The next time your code yields, the next call in the queue will be triggered.

浏览器上的JavaScript是单线程的(除非您使用web worker,而且其语法是显式的)。所以myFunction会一直运行直到它返回——有一些注意事项(继续阅读)。如果ajax层在myFunction运行时完成了一个操作(很可能是这样),并且需要调用回调,那么这个调用将被排队。下次代码生成时,将触发队列中的下一个调用。

It might seem, then, that we never have to worry about race conditions. That's mostly true, but there are subtleties. For instance, consider this code:

那么,我们似乎永远不必担心种族状况。这基本上是对的,但也有微妙之处。例如,考虑以下代码:

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

Since JavaScript on browsers is single-threaded, I'm guaranteed to get the load event when the image loads, right?

由于浏览器上的JavaScript是单线程的,所以我保证在图像加载时获得加载事件,对吗?

Wrong.

错了。

The JavaScript code is single-threaded, but the rest of the environment probably isn't. So it can happen that, having set the img.src, the browser may see that it has a cached copy of the image it can use, and so it triggers the load event on the img between the img.src = ... line and the img.onload = ... line. Since my handler isn't attached yet, I don't get the call, because by the time I've attached my handler, the event has already fired.

JavaScript代码是单线程的,但是环境的其他部分可能不是。设置img后,可能会发生这种情况。浏览器可能会看到它可以使用的映像的缓存副本,因此它触发img之间的img上的load事件。src =…线和img。onload =…线。由于我的处理程序还没有附加,所以我没有得到调用,因为当我附加我的处理程序时,事件已经触发。

But you can see the effect of queuing if we reverse those lines:

但是你可以看到排队的影响,如果我们颠倒这些线:

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

Now I'm hooking the event before setting src. If the event fires between the img.src = ... line and the doSomethingElse line (because the browser has the image in cache), the callback to my handler gets queued. doSomethingElse and doYetAnotherThing run before my handler does. Only when control passes out of my code does the queued call to my handler finally get run. The JavaScript code is single-threaded, but the environment is not.

现在我在设置src之前连接事件。如果事件在img之间触发。src =…line和doSomethingElse行(因为浏览器在缓存中有映像),我的处理程序的回调将进入队列。在我的处理器运行之前做一些其他的事情。只有当控件从代码中传出时,对我的处理程序的排队调用才会最终运行。JavaScript代码是单线程的,但是环境不是。

You can also yield to the host environment in non-obvious ways. For instance, by calling alert or its breathren confirm, prompt, etc. These functions stick out like the sore thumbs they are in modern JavaScript because they aren't event driven; instead, JavaScript execution is suspended while a modal window is shown. But as bobince points out in his in-depth discussion here, that doesn't mean none of your other code will run while that modal is showing. It's still single-threaded, but the one thread is being suspended in one place (by the modal) and used to run code elsewhere in the meantime; a very fine distinction indeed. (Bob also points to some event handling — his focus example — that seems to break this rule, but it doesn't. His example calls focus, which in turn calls the event handlers, and then returns; no different from you calling your own functions.) The key thing the items that Bob points out have in common is that your code has called into something in the host environment that does goes away and does something (shows a modal dialog, fires blur and focus handlers, etc.).

您还可以以不明显的方式屈服于宿主环境。例如,通过调用alert或它的breathren confirm、prompt等函数,这些函数就像现代JavaScript中的大拇指一样突出,因为它们不是事件驱动的;相反,在显示一个模态窗口时,JavaScript执行被挂起。但是正如bobince在他的深入讨论中指出的,这并不意味着在显示模式时,您的其他代码都不会运行。它仍然是单线程的,但是一个线程被挂起在一个地方(通过模式),同时用于在其他地方运行代码;这确实是一个非常细微的区别。(Bob还指出了一些事件处理——他的焦点例子——似乎打破了这条规则,但事实并非如此。他的示例调用focus,焦点反过来调用事件处理程序,然后返回;这和你调用自己的函数没什么不同。Bob指出的项目的关键之处在于,您的代码在主机环境中调用了一些东西,这些东西会消失并做一些事情(显示一个模态对话框,触发blur和焦点处理程序等)。

(alert and its breathren in particular cause all sorts of nastiness, particularly around focus and blur, and I recommend avoiding them in favor of more modern techniques (which can also look about 18x better).)

(特别的是,alert和它的呼吸系统会导致各种各样的不愉快,尤其是在焦点和模糊的周围,我建议避免使用它们,而采用更现代的技术(也可以更好地显示18倍)。)

So those are the caveats mentioned at the outset of the answer. And in particular, if myFunction calls alert, at least on Firefox the ajax completion callback will get run during the alert (it won't on most other browsers). If you're curious to try out what does and doesn't happen during alerts and such, here's a test page testing setTimeout and ajax; you could extend the tests to go further.

这些就是答案一开始提到的注意事项。特别是,如果myFunction调用alert,至少在Firefox上,ajax完成回调将在警报期间运行(在大多数其他浏览器上不会)。如果您想了解在警报期间发生了什么和没有发生什么,这里有一个测试页面,测试setTimeout和ajax;您可以进一步扩展测试。

#2


7  

These answers are all wrong [edit: at least 3-4 wrong when this answer was posted]. The XHR event is put in the event queue/pool. When the single-threaded javascript thread is not busy, it will grab the next events from the event pool, and act on them. One of those events will be your XHR "AJAX" request, which will trigger the callback, which will then execute. This is how all event-driven systems without interrupts work.

这些答案都是错误的。XHR事件放在事件队列/池中。当单线程javascript线程不繁忙时,它将从事件池中获取下一个事件,并对其进行操作。其中一个事件是XHR“AJAX”请求,它将触发回调,然后执行回调。这是所有事件驱动系统不中断工作的方式。

edit: Upvoting Joe's answer which links to Is JavaScript guaranteed to be single-threaded? and mentions the subtle edge-cases. Very informative.

编辑:向上投票乔的答案哪个链接是JavaScript保证是单线程的?并提到微妙的边缘情况。非常有益的。

#3


3  

Javascript kind of single threaded see Is JavaScript guaranteed to be single-threaded?. So the answer is NO, your event handler and your function could run at the same time, or they might not.

Javascript类型的单线程看到的Javascript保证是单线程的吗?所以答案是否定的,你的事件处理器和你的函数可以同时运行,或者它们不能同时运行。

#4


2  

The AJAX callback runs on the next event loop.

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

#5


0  

The ajax calls with be simultaneously. So when the ajax call is successful, the callback function is invoked which in turn invokes the the myfunction.

ajax调用同时进行。因此,当ajax调用成功时,将调用回调函数,该函数反过来调用myfunction。

#6


0  

You could quickly test this by putting an alert('first one'); alert('second one'); in both functions, and see which modal popup comes up first. If your code really is affected by the order, put some conditional checks in both to prevent / allow something. The speed of native js vs the speed of a full round-trip to and from the server is wildly different. Unless you have some javascript running in an infinite loop, the odds of the ajax call returning during your other function execution is tiny.

您可以通过设置一个警报(“第一个警报”)来快速测试这一点;alert('第二个');在这两个函数中,都可以看到哪个模式弹出窗口最先出现。如果您的代码确实受到顺序的影响,那么在两者中都进行一些条件检查,以防止/允许某些东西。本地js的速度与服务器往返的速度有天壤之别。除非在无限循环中运行一些javascript,否则在其他函数执行期间返回ajax调用的几率很小。

#7


0  

AJAX calls are "asyncronous" which means "fire off a call and let me know what you want me to call back when im done".

AJAX调用是“异步的”,意思是“启动一个调用,并让我知道您希望我在im完成时调用什么”。

so in short:

所以,简而言之:

function DoSomething() { AJAXCall(Callback); }

 ... some time passes then ...

function Callback() { Done(); }

Between those 2 function calls anything can happen, the callback will still be called when the response comes back because although the javascript runtime is single threaded the browser will stack calls to happen in some sort of order (likely the order they are made but not garanteed).

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

It's a shame i just pulled done my old website because i had classic example of a page making several ajax calls on load, as each call came back it would populate various portions of the page.

遗憾的是,我刚刚做了我的旧网站,因为我有一个经典的页面实例,它在加载时执行几个ajax调用,每次调用返回时都会填充页面的各个部分。

although each call was "attached" to the document loaded event only 1 call could be made at a time but the server could respond to any call in any order because the server could be multithreaded (and likely is).

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

Think of javascript as being a virtual box in which which the browser can pass a small lump of code, it can only run 1 lump at a time but it can run lots of scripts in whatever order it sees fit (generally this is unpredictable with multiple ajax calls because who knows when the server might come back with a result)

认为javascript是一个虚拟的盒子中,浏览器可以通过一小块代码,它只能运行1块一次,但它可以运行很多的脚本在它认为合适的(通常这与多个ajax调用是不可预测的,因为谁知道服务器什么时候会回来,结果)

#8


-1  

When the ajax succeeds and invokes myCallback, it will run synchronously. So myCallback is like other functions, you call it first it will run first or you call it last it will run last. THEY WILL NOT RUN AT THE SAME TIME.

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