Saturday, November 30, 2013

Surprises with JavaScript's Async Single Threadness

"Must wait till you be called for."
-- Shakespeare, Henry VIII
Act V, Scene II, Line 6.1

Quick question what is the output of the following JavaScript code?

for (var i = 1; i < 4; i++){
  setTimeout(function(){console.log(i);}, 0);

A) 1, 2, and then 3 in that order
B) 1, 2, and 3 in some order
C) 4, 4, and then 4 again
D) The example is wrong and will not even run!

Knowing myself I would bet on D, but the correct answer is drum roll ....


C:\async_examples\queueing\lib>node setTimeoutExample.js

Yep, the code above will output 4, 4, and then 4 again.  Why is this?

For normally everyday uses, JavaScript is single-threaded in all major implementations meaning: normal browsers, IE, Node.js, ...  Spending most of my career with Java I found this very surprising when I read about it in Async JavaScript by Trevor Burnham, which is where I got this example. (I do not expect to get anything for linking to the book, other than getting others to read it and write good JavaScript.)

OK, single-threading is fine, but why is the output not 1, 2, 3?!?  I mean we are setting the timeout to 0!  JavaScript uses queues for its asynchronous events and since it is single-threaded the code must complete before the queue is processed.

I believe a picture would be helpful right about now.

Looking at the flow above we see that once we are done with the loop, which is placing events on the timeout queue, the system then processes all the items in the queue.

Looking at the state of the memory after the loop, we see that the queue is full of console.log(i).  By the time that the console.log(i) is processed the value of i is 4.  Thus, we will get three 4's as our output.

The beauty of this type of model is that you do not have to worry about your code being interrupted.  The downside is that this is unlike what most programmers have used before.