38

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?

Vivian River
  • 31,198
  • 62
  • 198
  • 313

8 Answers8

56

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?

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.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I have a feeling browsers use an eventloop for this behaviour internally (like node.js). If this is the case you might want to talk about how eventloops work aswell. – Raynos Jul 14 '11 at 02:57
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.

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

Community
  • 1
  • 1
ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • I agree. Not ALL are wrong, but many are misleading. @icktoofay, your answer is definitely correct, so I +1ed your answer. Ninjagecko's answer is just a bit more robust. – beatgammit Jul 12 '11 at 03:27
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.

Community
  • 1
  • 1
Joe
  • 80,724
  • 18
  • 127
  • 145
  • 1
    While this is technically possible in some implementations, programmers should always assume that an evented model is strictly followed. Anything other than this leads to insanity. – beatgammit Jul 12 '11 at 03:33
2

The AJAX callback runs on the next event loop.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • 1
    +1 for mentioning the event loop. Many people don't understand how evented systems work. Perhaps you could include a link that explains javascript's evented-ness? – beatgammit Jul 12 '11 at 03:27
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.

Brad Ruderman
  • 2,053
  • 2
  • 15
  • 22
  • 1
    Though mostly right, unfortunately this misunderstands the question: the `myFunction` is completely independent of the callback, and is not being invoked by the callback. – ninjagecko Jul 12 '11 at 03:49
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.

ElonU Webdev
  • 2,451
  • 14
  • 15
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".

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).

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.

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)

War
  • 8,539
  • 4
  • 46
  • 98
-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.

kazinix
  • 28,987
  • 33
  • 107
  • 157
  • Synchronous is a scary word with lots of weird connotations. Perhaps this could be explained a little better? Like mention how events in the queue are executed in turn or something. – beatgammit Jul 12 '11 at 03:28
  • @tjameson - We are in a specific topic, I think I can use synchronous. :) I explained it though, thanks! – kazinix Jul 12 '11 at 03:47
  • @domanokz- I didn't vote down, that was someone else. It wasn't technically incorrect, so I just left a comment suggesting how to improve it. – beatgammit Jul 12 '11 at 04:12
  • @domanokz: You can never know who voted something down. It's frequently the case that one person will downvote, and a *different* person will leave a comment. [ And no, it wasn't me, either. :-) ] – T.J. Crowder Jul 12 '11 at 04:20
  • "Ajax request is the only asynchronous in your program" - what about timeouts? (And no, not me either.) – nnnnnn Jul 12 '11 at 04:25
  • @tjameson, @T.J. @nn - Okay, somebody did. Isn't that a part of ajax request? I mean the timeout? Anyways, I assume, based on Rice's question, he has an AJAX request, a callback function and the other function, that's all. I'll fix it anyway, to avoid confusion. – kazinix Jul 12 '11 at 04:49