Ajax, javascript and threads : the final truth

Since I have written Ajax and javascript don’t use thread, one of my reader (BK) told me that I was wrong. Here’s the final truth.

What I said

If javascript runs some code that takes 5 seconds to execute and an ajax response arrives at 2 seconds, it will take 3 seconds before it will be executed (before the callback function is called).

Example. We have a f() function that is incredibly long to execute (5 seconds) because it has a lot of code.

1. function f() is started
2. f() makes an ajax call
3. f() is still executing since 2 seconds
4. the response from the server arrives at the third second
5. f() is still in execution for 3 seconds
6. the callback function for ajax is called

What he said

Briefly, say I have CallPage1, CallPage2 and DoSomething. Both CallPage are async.

CallPage1 called
CallPage2 called
DoSomething called
CallPage1 Returned (DoSomething is now paused)
DoSomething ended
CallPage2 Returned

The DoSomething() function is paused when the ajax response arrives. The callback for the ajax is called and only then, DoSomething() resumes its execution.

That didn’t make sense to me. Javascript is really sequential and it would not do that kind of complex stuff. But, I had to be sure.

The test

I made a simple page to test it all.

1. Loop from 0 to X (user defined). X should be a big number.
2. The first loop, it makes an ajax request
3. The loops will finish someday
4. The callback for the ajax will be called someday

I didn’t know what to expect : will the callback function be called before or after the loop?

The result

I ran the script a lot of times with a lot of numbers and it was always the same thing : the callback function waits for the loop to be over before it is executed. It means that the current function is not paused.

Now it’s your turn

I want you to take a look at the script (complete php code) (I know it’s poorly written, it’s just a test) and tell me if I’m wrong or if I’m right.

Thanks to you all!

Commentaires

  1. Frank June 12 2007 at 10:15:53

    Well, executing the script multiple times makes it clear in my mind that Dan is right in his assumptions. The callback waits until the method is done executing. TheTruth() is never paused when the AJAX call returns.

  2. Patrick Fitzgerald June 12 2007 at 14:01:46

    Now try throwing in an alert:

    if (i == 500) { alert(’foo’); }

    If theTruth() is paused doing an alert, then the callback will occur.

    So, you can’t guarantee that the callback will occur after the code runs!

  3. Dan (maintainer of Javascript Kata) June 12 2007 at 17:43:04

    @Patrick, do you know any other statement that could have the same effect as alert() on javascript?

  4. Rob Desbois June 13 2007 at 03:52:28

    I asked this exact question yesterday on the jQuery mailing list and got the response that JS isn’t threaded so it will behave as your tests (and my own) show.

    @Patrick, what did you test that on?
    Under Firefox 2 I tested this:

    ====
    send AJAXrequest
    alert

    function ajaxCallback {
    change the body background colour
    }
    ====

    Until I clicked the alert box, the callback was not run. Firebug didn’t ’see’ the response until after the alert was closed. IE6 showed the same result.

  5. sb_doc June 13 2007 at 08:32:56

    @Dan & Patrick, try to make a syncronous (yes, NOT asyncronous) XHR instead of an alert (with the async response returned before the call of the sync send).
    In my tests (win XP Pro SP2) browsers behave differently:
    - IE6, IE7 and FF3a5 (aka Gran Paradiso alpha 5) theTruth() is paused and the callback executed;
    - FF2.0.0.4, FF1.5 and Opera 9.1 theTruth() runs to the end and then the callback executed.

  6. sb_doc June 13 2007 at 08:35:05

    Sorry… Opera version is wrong: it’s 9.21 not 9.1

  7. Dan (maintainer of Javascript Kata) June 13 2007 at 09:06:02

    @sb_doc
    I heard somewhere that synchronous request are not “enabled” in Firefox. Anyway, why would we want to do synchronous?

    @Rob Desbois
    Thanks for the test! I’ll try it with my script just because I’m curious.

  8. Patrick Fitzgerald June 13 2007 at 09:08:17

    @Dan, confirm() has the same effect, but those are the only ones I know that can “pause” a script while still allowing other code to execute.

    @Rob, I tried this on Firefox 2 using a modified version of Dan’s script (using dojo to perform the ajax request). I can’t reproduce your observation; instead of changing the background color try setting innerHTML on something and see if that occurs.

    @sb_doc: good point (but I was unable to reproduce your observation in IE6).

    I think the lesson learned is never to rely on any particular order of execution when using callbacks, especially if you don’t know what code will run before your callback returns.

  9. Dan (maintainer of Javascript Kata) June 13 2007 at 09:35:33

    @Rob
    Patrick was right. The reason why the background-color didn’t change until you click OK is because DHTML is executed when there’s nothing else to execute.

    @Patrick
    You were right! When I alert(), the callback is called.

    You have the right conclusion : never expect some code to run before or after another.

  10. Patrick Fitzgerald June 13 2007 at 10:07:46

    It gets really interesting if your callback takes a long time to run, because after the user clicks ok on the alert, control does not pass back to theTruth() until the callback finishes!

    Also note that, in addition to async AJAX callbacks, this behavior occurs with setTimeout() and setInterval().

    That is, if you set a timeout of 1 sec, your code might not actually run exactly 1 sec later, it might be held up by some other code that is running. If an alert occurs, your timeout can jump in and start running.

  11. sb_doc June 13 2007 at 10:08:40

    @Dan: it’s just another way to confirm “the right conclusion” :) (and to lean that syncronous call doesn’t mean “atomic”).

    @Patrick: IE6 behaviour was observed on Win2000 SP4.

    I quote “the right conclusion”!

  12. BK June 13 2007 at 12:07:58

    I suppose the reason why I had this behavior in the past could have something to do with the fact that being in the debugger, it was a bit like having an alert.

    BTW, if you have a 5 second function, try to split it in many sub functions with a state object that you pass around. This way, you can easily use window.setTimeout with a very short delay between each part. This way, you will give time to some async request to come in and give the user a more responsive experience. When you look at it, it is a bit like simulating shared time threading.

    For those with experience in VB, this would give a result a bit like the DoEvents function. If Dan is up to it, I think a little wrapper could easily be developped to manage the in-between calls.

  13. Dan (maintainer of Javascript Kata) June 13 2007 at 12:35:18

    @BK
    I used to split a long function with a very long loop in small chunks because I didn’t want the browser to froze. You had a brilliant idea in including this in a library.

  14. Remy Sharp June 14 2007 at 06:51:43

    Thanks for taking the time to carry out the test. I always thought that using AJAX or a setTimeout/Interval would create a threaded app.

    I thought that I might be able to change this code to use setTimeout to allow the browser some ‘breathing’ time to execute the callback. It does work, but from the test I ran, the processing is simply handed over to the callback and then back to theTruth when the callback completes.

    It’s a bit rough around the edges, but here’s the same test using timeouts to attempt to create a threaded app:

    http://remysharp.com/wp-content/uploads/2007/06/thread_test.html

    The result - JS doesn’t thread.

    Thanks again.

  15. Pablo Cabrera June 14 2007 at 10:03:49

    To prevent the alert, confirm, etc… from pausing the script execution, you could overwrite the default function with some custom dialogs, so you never get the default dialogs halting your script. This way you can guarantee that your callbacks will execute just after your current running code

  16. Patrick Fitzgerald June 14 2007 at 10:22:53

    @Pablo: you might be able to do that, and it would probably work in today’s browsers, but I don’t think there’s anything in the spec that says the callback has to occur after your code runs. What if, in a future release, the browser changes this behavior?

    Also, if you are writing modular code, you might not know if an alert will occur.

  17. Alex Hernandez June 14 2007 at 11:49:32

    @Dan :
    “Anyway, why would we want to do synchronous?”.

    What if you have code that need to use a returned value from your request’s response? you need for that call to end before keep
    going with the execution of your code. What I do with Prototype,
    is to set “asynchronous: false” in my request (is set to true by default and the purposes of AJAX), so the code after the call will execute quen the request is done.

    .::AleX::.

  18. […] Ajax, javascript and threads : the final truth | Javascript Kata (tags: javascript ajax) […]

  19. Jon June 14 2007 at 21:43:10

    I hacked at this for an hour and have arrived at the same conclusion - javascript just doesn’t do threads.

  20. Mike Griffiths June 15 2007 at 05:49:05

    Why did anyone think that JavaScript was executed in multiple threads by the browsers? The documentation of XMLHTTPRequest (et al) clearly states that the process waits for the return of the Ajax “request” or a timeout.

    The new Google Gears beta includes provision for the execution of multiple JavaScript threads - check it out as this was probably the most important component of the Google Gears “package”.

  21. BK June 15 2007 at 06:36:19

    By design, any asynchronous call, somewhere, generates a new thread. There is no other way to do this (if you know one, please tell me). BUT, on the other hand, since JS itself is single threaded, any request coming from an async thread is queued in a call queue.

    About the fact that “The documentation of XMLHTTPRequest (et al) clearly states that the process waits for the return of the Ajax “request” or a timeout” could you give your reference? I’m quite curious to see this on the MS site about the “async” call because then, what would be the difference with the synchronous call. This sound a bit absurd.

  22. Calvin Spealman June 15 2007 at 23:20:36

    I actually thought this was already a known fact. I suppose if anyone is doubtful, having a test to show the reality of it is a good thing.

  23. Andrey June 18 2007 at 06:33:25

    @BK: “By design, any asynchronous call, somewhere, generates a new thread. There is no other way to do this (if you know one, please tell me).”

    Browser has a pool of threads doing all download jobs (pages,images,css,js and any other files, _including_ ajax calls). Calling new XHR just schedules new job to this pool. On return this task ‘injects’ callback address in the queque of waiting tasks of ‘cooperative multitasking’ roundrobin of JavaScript evaluator.

    Btw, read about ‘completion ports’ and ‘fibers’ - these are used in the Firefox NSPR runtime.

  24. Alon Weiss June 18 2007 at 10:52:09

    Silverlight supports running JScript natively, WITH threading support. Shouldn’t take too long to compile an example out of this.
    I wonder if we can build a wrapper that will get a string that will be eval’d at another thread, with another object as an execution context and another one as a parameter list.

  25. FlameBot June 24 2007 at 11:37:21

    Hey, why don’t you all just read the browsers’ source code to find out how the threading model is done?

    Oh, right…

  26. Kevin Galligan June 28 2007 at 13:53:06

    “never expect some code to run before or after another”

    That’s not exactly true, though. Right? Yeah, if you have ‘alert’ or ‘confirm’ in there, one browser might let other methods run, and another won’t, but without calling those, your ajax callbacks aren’t run until your other javascript is done. Right? We have a case where this is critical. If its not true, I need to implement a queue method calling mechanism, which isn’t the end of the world, but isn’t fun either.

  27. BK July 3 2007 at 15:00:06

    No matter if it always happen, sometimes happen or never happen, the best thing for a piece of code to never break is to try to anticipate all cases.

    In this particular situation, all cases implies may different browsers, each with their own implementations, built in different “computer eras”, that are still evolving and mostly within a language that is actually in a major second life.