-2

I was expecting the output to be 3->2->1 but instead my output is 1->3->2

Why I am getting differently?

setTimeout(() => {
  console.log(`1 work is done`);
  
  setTimeout(() => {
    console.log(`2 work is done`);
  }, 3000);
  
  setTimeout(() => {
    console.log(`3 work is done`);
  }, 1000);
}, 5000);
Andreas
  • 21,535
  • 7
  • 47
  • 56
zahid
  • 37
  • 6
  • [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) -> [Proper formatting](https://stackoverflow.com/help/formatting) is one part of that – Andreas Sep 04 '21 at 16:01
  • 1
    I'm getting this 1 work is done 3 work is done 2 work is done – Noam Yizraeli Sep 04 '21 at 16:03
  • 1
    Why should it start with `3`? That one is _in_ the `setTimeout` that logs `1` - after 5 seconds. So `3` as the first is impossible... – Andreas Sep 04 '21 at 16:04
  • my expectation was that events with the least timeout should be first pushed to the event queue. As it was doing for 3 and then 2. Does it mean whenever an async event gets created, no matter what the time out is set for the 1st event, will always get executed first as in this case? – zahid Sep 04 '21 at 16:32

3 Answers3

1

It's happening in 1-3-2 because the TImeout for "1" initiates the other 2 Timeouts only after it's run.

To simplify things a bit, lets look at it as a method.

setTimeout1() {
  console.log(`1 work is done`);
  
  setTimeout3()
  {
    console.log(`3 work is done`);
  }
  
  setTimeout2()
  {
    console.log(`2 work is done`);
  }
}

It really doesn't matter that your first Timeout is a Timeout, since the other 2 are nested into it. Those other 2 Timeouts aren't even instantiated until the first one runs. I've reordered "2" and "3" because that's the order you wanted them to run in. The Timeouts, as you are trying to show, don't care what order they are instantiated, but this does.

If you really wanted to get them to run in order and simultaneously, you'd have to set them up completely independently. This would set up independent "threads" or "processes" for each task/timeout. JavaScript doesn't actually do multithreading, though, but it's an approximation. Even modern browsers still don't do true multithreading, but come close.

This allows each task to be done at the time you put into the Timeout, so "3" would appear after 1 second, "2" would show up after 3 seconds, and "1" would finally show up at the 5 second mark.

setTimeout(() => {
  console.log(`1 work is done`);
}, 5000);

setTimeout(() => {
  console.log(`2 work is done`);
}, 3000);

setTimeout(() => {
  console.log(`3 work is done`);
}, 1000);

Or you could iteratively nest them in the order you want them to run, if you want them to run only after the others run. This would be running them in series and not even really attempting multitasking/multithreading/parallel processing, at least not with this simple of an example.

Here, your Timeouts are additive, so while "3" would still show up after 1 second, "2" would show up after 4 seconds due to it's 3 second timer being started only after the initial 1 second delay. Similarly, "1" would be displayed after 9 seconds, being set up only after the "2" had already run.

setTimeout(() => {
  console.log(`3 work is done`);
  
  setTimeout(() => {
    console.log(`2 work is done`);

    setTimeout(() => {
      console.log(`1 work is done`);
    }, 5000);
    
  }, 3000);
  
}, 1000);

Let's look at your original code again. It's firing off your first Timeout to wait 5 seconds, and then only after that delay does it start the delays for "2" and "3". Trying to say it yet another way, "1" has to run before the code for the other 2 even start their delay. What you've set up is a thread that starts 2 other threads. This first thread is in series with the other two, but then they ("2" and "3") run in parallel with each other once "1" is completed.

setTimeout(() => {
  console.log(`1 work is done`);
  
  setTimeout(() => {
    console.log(`2 work is done`);
  }, 3000);
  
  setTimeout(() => {
    console.log(`3 work is done`);
  }, 1000);
}, 5000);

Maybe look at it like power strips. Each Timeout is a power strip with multiple outlets (lines of code). In your original code, you have power strips "2" and "3" plugged into power strip "1". If you want them to run independently, you have to plug them into different wall sockets, not each other. And if you want them to start one after the other, then you can't plug 2 strips into the same other strip, you have to plug them into each other in the order you want them to run.

And just like plugging multiple power strips into each other, it has pros and cons. In a real power strip, for an example of a "con", you're looking at using too many devices and drawing too much power. In a programming sense, you're adding the delays together to change your timing, so if you change one delay value, you end up changing everything that comes after it, too.

For a "pro", using real power strips, you can space out your devices and get power to a longer run of devices, such as multiple (low power) monitors on a long table. In programming, you can make sure that multiple long running tasks happen in order without freezing the browser while they happen.

Running Timeouts like this definitely is tricky. There are definitely instances when you want to have everything running independently and at the same time, and other instances when you need to make sure those tasks happen in a specific order. This takes some planning and experience to figure out what's "best" for your use, so try out different things/combinations to see what works and what doesn't.

computercarguy
  • 2,173
  • 1
  • 13
  • 27
0

The setTimeout() timings are not correct. Your parent setTimeout() method it's set to execute after 5000 ms, then it enters the function and the first one it triggers is the one without Timeout which is your first console.log() , after that it executes the second one which is the third console.log() and finally the console.log() in the middle.

In summary, you forgot to setTimeout() to the first console.log(). If you want that one to be the last, it should have a Timeout bigger than the second and third. Try the following snippet:

setTimeout(() => {
  
  setTimeout(() => { console.log("1 work is done") }, 2000);
  setTimeout(() => { console.log("2 work is done") }, 1000);
  console.log("3 work is done")
  
}, 1000);
Gass
  • 7,536
  • 3
  • 37
  • 41
-1

I will suggest you use promise instead of setTimeout. For your code to work rearrange the setTimeout like this

setTimeout(() => {
  console.log(`3 work is done`);
  
  setTimeout(() => {
    console.log(`2 work is done`);
  }, 1200);
  
  setTimeout(() => {
    console.log(`1 work is done`);
  }, 1500);
}, 1000);
Peter
  • 1,860
  • 2
  • 18
  • 47
  • OP wasn't asking _how_ to get the code to work, they were asking why the output was not what they expected. – Andy Sep 04 '21 at 16:16