1

I was perusing over a set of online javascript interview questions and noticed the following question:

function printing() {
  console.log(1); 
  setTimeout(function() { console.log(2); }, 1); 
  setTimeout(function() { console.log(3); }, 2); 
  setTimeout(function() { console.log(4); }, 0); 
  console.log(5);
}
printing();

I expected the following code to print the following to the console: 1,5,4,3,2 My reason is that console.log(1) and console.log(2) is executed first while the setTimeout is sent to the eventloop where it waits for everything to finish first. Once 5 is printed, JS will look at the queue and 4,3,2 would push/pop in next.

However, on my Chrome browser I noticed 1,5,2,4,3 comes out instead.

I'm confused, but at the same time have a hunch that it may be due to the small increment of timeout delay that is causing the hiccup (perhaps a browser thing?). My reason for that is because I added two following zeroes to each number such that the delays become 100, 200, and 0.

Can anyone clarify what's going on under the hood, and any gotchas I should know about the delays?

bigbitecode
  • 253
  • 5
  • 16
  • 1
    Pretty sure the minimum valid value for a timeout is 1, so the 0 is shifted to 1 and therefore happens after. Not sure. I don't use timers less than 16ms anyway (60Hz) since that's the default timer resolution on Windows and I don't feel like using the high-resolution timer just for the sake of it. – Niet the Dark Absol Oct 13 '15 at 17:01
  • I noticed the following link where the minimum is 4ms and 10ms depending on the browser: http://stackoverflow.com/questions/9647215/what-is-minimum-millisecond-value-of-settimeout – bigbitecode Oct 13 '15 at 17:11
  • It's probably worth noting that in Section 6.4 of the [w3 spec](http://www.w3.org/TR/html5/webappapis.html) it states `... timeout is less than 4, then increase timeout to 4` (if your ms value is 0-3 according to spec it will be set to 4) and with that, you might find the following on Javascript timing helpful [How Javascript Timers work](http://ejohn.org/blog/how-javascript-timers-work/) – Arthur Weborg Oct 14 '15 at 13:56

2 Answers2

3

Here I'll give you an example of how the execution goes:

  console.log(1);                                   // Run log "1"
  setTimeout(function() { console.log(2); }, 1);    // Add to queue timer1
  setTimeout(function() { console.log(3); }, 2);    // Add to queue timer2 
  setTimeout(function() { console.log(4); }, 0);    // Add to queue timer3
  console.log(5);                                   // Run log "5"
  // In queue [timer1, timer2, timer3]

  // [tick timer 1 => 0 time left => execute] log "2"
  // [tick timer 2 => 1 time left]
  // [timer 3 => 0 time left => execute] log "4"
  // [tick timer 2 => 0 time left => execute] log "3"

Functionally setTimeout(... , 0) and setTimeout(..., 1) will work the same way. When we tick each timer in the "timeout queue" we also check if there is any time left. So setTimeout(..., 1) will tick and execute while setTimeout(... , 0) will simply execute.

Spencer Wieczorek
  • 21,229
  • 7
  • 44
  • 54
  • Ah, that makes a lot of sense. Since JS is synchronous, it goes through the order of the timer queue and expires timer1 first causing it to execute. Really helpful comments, thanks! – bigbitecode Oct 13 '15 at 17:11
  • It is the same for each browser / engine ? my firefox log `1 5 4 2 3` – Anonymous0day Oct 13 '15 at 17:14
  • 1
    @Anonymous0day No it's not. Different browsers can handle the timers differently. What I explained above is how it happened in the OP browser (which I assume would be chrome). It looks like Firefox will tick each timer in the queue differently (it could be ticking the one with the smallest time left first, but that's a guess). – Spencer Wieczorek Oct 13 '15 at 17:19
  • @Spencer Wieczorek great i was not aware, and now i am ! thank you for your explanation ! – Anonymous0day Oct 13 '15 at 17:24
1

You have to understand the call stack. All function calls are placed on the call stack, if the stack is empty then the function is called. If the stack has entries then the function will not be called until the current calls on the stack are completed.

Timeouts place calls on the call stack when they timeout. They do this asynchronously. Thus a call can be placed on the call stack during the current execution.

The timeouts are not prioritised and first on the stack is first to execute. The 1 millisecond timeout is beating the 0 millisecond to the call stack and hence is executed first.

Blindman67
  • 51,134
  • 11
  • 73
  • 136