Which fires first, the setTimeout() created earlier or scheduled for sooner?

- 1 answer

Ad

Consider the following..

var timeoutA = setTimeout(functionA, 200);

// CPU intensive task blocks the event loop for ~50 ms

var timeoutB = setTimeout(functionB, 100);

// CPU intensive task blocks the event loop for ~200 ms

// Now what?

So we have a situation where there are two outstanding timeouts, both scheduled to fire at some point in the past. One (timeoutA) is the older of the two since it was created first but the other (timeoutB) was scheduled to run sooner, even though it was created second.

Which timeout will "win" and execute its function first? (Specifically in node.js v5 but would be interested to heard about other engines also).

There are several existing questions about the execution order of js timers but none address the situation in which their creation order and scheduled execution order conflict. These questions deal with instances where the timers are created and scheduled to run in the same order:

Ad

Answer

Ad

The way I understand things in JS with async execution is as follows.

There is an events hash, which has all of the events async tasks listed in it (things like set timeouts, ajax requests, click handlers etc..). Then there is a queue which holds all of the 'fired' events (callbacks that are ready to be run, set timeouts whose time is up, click events that have been heard...). And finally there is a run loop which is constantly managing these two data structures by doing two things: First, it is repeatedly checking if an event in the events hash needs to be put into the queue (like the time has passed for setTimeout or the ajax request has resolved). Second, if the queue has a callback that needs to be called, it will dequeue and call the next function in the queue, once per loop.

Now getting into the meat of your question, in what order do the events get put into this queue?

Basically when a setTimeout is invoked, an event is added to the hash with a certain 'time signature', that is the current time + the amount of ms passed in to the timeout parameter. Now when the run loop gets to the point where it will add things to the queue, if it sees multiple setTimeouts ready to be enqueued, it will enqueue the one that has an earlier 'time signature' first, and then also enqueue the other one, and any other events that are ready (for example if a click event happened in between the two aforementioned 'time signatures' that events' callback would go off in between the two setTimeouts). And so, bringing this back to your example above, even if we did have a cpu intensive task in the middle of these two setTimeout functions you called, the second setTimeout with the 'time signature' of +150ms is less than the first one which has +200ms, and therefore the second call to setTimeout would have its callback higher on the queue, and it would be called first.

Ad
source: stackoverflow.com
Ad