Suppose I write some JavaScript that performs an AJAX call with myCallback
as a callback method to execute when the AJAX succeeds.
Suppose then that some other JavaScript method called myFunction
is being invoked on my page when myCallback
is invoked asynchronously.
Does one operation take precedence over the other? Do they both run at the same time? What happens?
When you make an AJAX request, your browser sends an HTTP request to a given address. The server on the other end of the request responds, and returns the data to your browser. This is the same thing that happens when you navigate to a new web page.
The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, $. ajax returns immediately and the next statement, return result; , is executed before the function you passed as success callback was even called.
Ajax interactions are initiated by JavaScript code. When the Ajax interaction is complete, JavaScript updates the HTML source of the page. The changes are made immediately without requiring a page refresh.
ajax({ async: true, contentType: 'application/json; charset=utf-8', type: "POST", dataType: 'json', data: JSON. stringify(arrays), url: "MyHandler. ashx", success: function (result) { b = true; }, error: function () { alert('Error occurred'); } });
Suppose then that some other JavaScript method called
myFunction
is being invoked on my page whenmyCallback
is invoked asynchronously.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.
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?
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.
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.
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
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).)
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.
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.
edit: Upvoting Joe's answer which links to Is JavaScript guaranteed to be single-threaded? and mentions the subtle edge-cases. Very informative.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With