4

I've know versions of this question has been discussed, and I think this is unique. Why does a delay of 0, still causes the below behavior.

for(var i = 0; i <3; i ++) {
  console.log(i, 'started');
  setTimeout(()=> {
    console.log(i);
  },0)
  console.log(i, 'done');
}

console.log('loop over');

   // 0 started
   // 0 done
   // 1 started
   // 1 done
   // 2 started
   // 2 done
   // loop over
   // 3 3 3 

Here is what I think I know so far:

Quoted from MDN in respect to setTimeouts position on the stack:

This is because even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity; not immediately. Currently-executing code must complete before functions on the queue are executed, thus the resulting execution order may not be as expected.

Am I correct in saying the for-loop and any synchronous code is placed on the call stack before setTimeout, AND even if you set the delay to 0, setTimeout will always run only after the for-loop has completed? Otherwise, why would a delay of 0, still result in the above behavior?

Thanks!

EDIT:

After getting started in the right direction, I found a few videos and a nice little tool that shows you the event loop and how it relates to this example code. Here is the JS runtime simulator: loupe

Brandon
  • 1,747
  • 2
  • 13
  • 22
  • In other languages the setTimeOut acts same as here. We use this behavior to be sure all other methods of all classes had called before the our newFunction calls and thwn we don't need to find the last called method. – MESepehr Mar 17 '18 at 03:20
  • 3
    Does this answer your question? [Why doesn't setTimeout(.., 0) execute immediately?](https://stackoverflow.com/questions/36904773/why-doesnt-settimeout-0-execute-immediately) – Heretic Monkey Dec 09 '21 at 13:47

2 Answers2

3

JavaScript, both in the browser and on the server, runs as an event loop. The runtime is constantly polling for events. Events consist of user actions (e.g. DOM element x was clicked), I/O (data came back from I/O or ajax call), and timer events (in this case). setTimeout(fn, 0) simply adds an event to be processed by the event loop at minimum when 0 milliseconds have elapsed. It will always execute after the current event has been processed.

john_omalley
  • 1,398
  • 6
  • 13
  • Perfect. I’ve found numerous articles expanding on what you were saying with this exact example. Thank you very much! – Brandon Mar 17 '18 at 02:56
  • I found a nice runtime simulator that shows the call stack and how it relates to this code. Just like you said, the for loop keeps the stack filled, and until all your code is done, the stack isn't empty, and the event loop can't grab any of the queued events. I posted the runtime sim above. – Brandon Mar 17 '18 at 04:05
0

Am I correct in saying the for-loop and any synchronous code is placed on the call stack before setTimeout

To be pedantic, setTimeout() itself gets called synchronously, and placed on the callstack right after console.log(i, 'started'); . It's the settimeout callback (in your case console.log(i)) that gets queued and called asynchronously.

gawicks
  • 1,894
  • 15
  • 22