-2
    setTimeout(() => {
        console.log(1);
        setTimeout(() => {
            console.log(2);
            setTimeout(() => {
                console.log(3);
            }, 1000);
        }, 1000);
    }, 1000)

Why this code allows you to console.log in every second sequentially? I expected the code would run 1, 2, 3 at the same time since all the timers were set to 1000 millisecond.

Kinta
  • 57
  • 1
  • 6
  • 2
    "Wait one second and print 1, then wait one second and print 2" should happen in two seconds. – VLAZ Aug 01 '21 at 12:37
  • Does this answer your question? [setTimeout or setInterval?](https://stackoverflow.com/questions/729921/settimeout-or-setinterval) – Amruth Aug 01 '21 at 12:40
  • 3
    Well, they're nested. The second timeout gets *scheduled* at the same time the `console.log(1)` runs. And it gets scheduled 1000ms ahead from the time of scheduling, not some fixed initial point in time. – Bergi Aug 01 '21 at 12:45
  • Did you also try to run code without nesting? That would have the outcome you describe. – Bergi Aug 01 '21 at 19:04
  • @Bergi yes, i did. I got rid of all the nesting and ran all in once. That actually confused me how nesting delays each timer. I was thinking all the code would get read line by line since JavaScript reads code line by line and never skip any single of code as i have understood. – Kinta Aug 02 '21 at 02:43
  • 1
    @Kinta code is executed line by line BUT code inside the function isn't execute until the function is called. – Yousaf Aug 02 '21 at 05:08
  • @Yousaf i see! i didnt see that point. Thats why the nesting looks like it is delaying the timers but what it does is just execute function by function in order. Thank you – Kinta Aug 02 '21 at 06:57

2 Answers2

0

You set the 2nd timer inside the 1st timer's body, so after 1000ms have already passed. Therefore it runs a second later than the 1st timer. Same story with your 3rd timer.

If you'd want them to run at the same time, you need to call setTimeout at the same time. And "same time" as in "as close to each other as possible given how timers work". If you truly want to run them sequentially at once, use a single setTimeout.

Kelvin Schoofs
  • 8,323
  • 1
  • 12
  • 31
0

Delay argument passed to setTimeout is the minimum amount of time it will take before the callback function is executed; it's not the actual time at which the callback will run.

Callbacks run in the order in which their timer expires and they get pushed into the task queue. From the task queue, they get pushed on to the call stack when the stack is empty.

Callback that is pushed first in the task queue is the first to get pushed on to the call stack. Consequently it is the first to get executed.

Why this code allows you to console.log in every second sequentially?

That's because each inner setTimeout callback also needs to account for the delay of the wrapper setTimeout.

The callback function of the second setTimeout has a delay of 2 seconds because the second setTimeout is called after the first timer expires after 1 second.

Similarly, the inner most setTimeout has a delay of 3 seconds.

Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • Is there any reason why the second setTimeout is called after the first timer expires after 1 second rather than not waiting for it to expire? I checked the code with debugger, and as you said second and third setTimeout never got executed and even read before the previous setTimeout finishes it's timer. – Kinta Aug 01 '21 at 13:49
  • 2
    @Kinta yes, there is. Because the first timeout has to fire in order to schedule the next timeout. If I give you a box that says "open after 1 minute", you need to wait one minute to open it. When you open it if you see another box with the same not "open after 1 minute", you need to wait another minute to open it. That is how execution works - each function is a box. You do not process the inside until you run the function. – VLAZ Aug 01 '21 at 13:57
  • 2
    @Kinta the analogy presented by VLAZ in the comment above should help you understand what's going on in your code. Since the 2nd `setTimeout` is called _inside_ the callback function of the first `setTimeout`, 2nd `setTimeout` is only called when the callback function of the 1st `setTimeout` executes and that happens approximately _after_ 1 second. You can't expect any code inside the callback function of the 1st `setTimeout` to execute _before_ the callback is actually invoked. – Yousaf Aug 01 '21 at 14:30