Thursday, June 14th, 2007
Ajax, javascript and threads : the final truth
Dan Simard has been writing about threading and JavaScript and came up with his Final Truth.
Dan has an example that has a long running function that fires of an XHR request at the beginning. Will that response come back when it is done, or will it wait for the method to complete.
There are many comments comparing various browsers, and how things change when you change between synchronous and asynchronous calls.
The truth seems to be:
- You can’t trust it to happen one way in all browsers / scenarios
- Please split up your functions :)












Is this really news to anyone? If you hog the CPU, it’ll block asynchronous stuff, such as XMLHttpRequests and setTimeouts. This is also quite consistent across browsers and platforms. (The alert() just temporarily stops your scripts from hogging the CPU until you dismiss the dialog.)
As for the breaking up of functions, I’m personally getting into the habit of using callbacks for everything:
function foo () {
// does stuff…
// calls another function
sleep(10, function () {
// rest of a goes on here after 10 seconds
});
}
function sleep (secs, callback) {
// sleep returns by calling a’s callback
setTimeout(callback, secs * 1000);
}
This way, it doesn’t matter if a function does synchronous or asynchronous stuff. You give every function a callback and it will return using that callback. The callback is kind of a continuation.
One problem is that this quickly builds up a huge call stack. You can get rid of the call stack by calling a callback with setTimeout.
Just a minor typo…
“a long running function that fires of an XHR request”
should be:
“a long running function that fires off an XHR request”
tx
Brendan Eich wrote an article about threads a couple of months ago…
http://weblogs.mozillazine.org/roadmap/archives/2007/02/threads_suck.html
c’mon guys …
for(var
nullable = null,
i = 0,
loop = 500000,
timeOut = setTimeout(function(){alert(nullable)}, 1);
i
… oops …
for(var
nullable = null,
i = 0,
loop = 500000,
timeOut = setTimeout(function(){alert(nullable)}, 1);
i < loop; i++
) {
if(i + 1 === loop)
nullable = “Hello World”;
};
The browser JS engine has a queue that it uses to process events (ajax responses, and setTimeouts count as events here). The queue just processes one event after another, one at a time. Each time an event is finished (which may take a lot of time as you observed), it will execute the next one. That is why you observe this behavior.
tim: JS isnt tail recursive? also have you considered using DOM synthetic events as a message passing idiom instead building up some tower of babel in callbacks..
Kris, it’s not a “so perfect” answer because if You generate a modal event inside long execution code (i.e. alert(”go on, async queue”);) ajax, as intervals, starts while function execution is “blocked” :-)
for(varnullable = null,
i = 0,
loop = 500000,
timeOut = setTimeout(function(){alert(nullable)}, 1);
i < loop; i++
) {
if(i + 1 === loop) {
// comment this alert to read Hello World
alert("nullable not yet setted");
nullable = "Hello World";
}
};
You can implement a form of multi-threading in javascript, by having your code voluntarily yield execution and a scheduler object to give each thread some time.
Neil Mix wrote a library to allow this in javascript. I blogged about it at: http://blog.monstuff.com/archives/000315.html
He probado el código de ix en FF e IE y el comportamiento es el esperado: la ejecución de la función pasada en el setTimeout sólo ocurre cuando el bloque de código que la “lanza” ha terminado. Es decir, los alert no permiten que los asincronos “expropien” al bloque de código que ejecuto el alert.
var nullable = null;
var loop = 500000;
var timeOut = setTimeout(function(){alert(nullable)}, 1);
for(var i = 0;i