简体   繁体   中英

Pipelining setTimeout in node.js

I am writing a node.js console application. I have two setTimeout functions as follows.

setTimeout(function(){
    process.stdout.write('\n\nJokes Apart !!!\n\n');
}, 2000);

setTimeout(function(){
    process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 1000);

What I actually intend is, the first message should come after 2 seconds. After that, the second message should appear after 1 second. But what's happening is, the second message appears after 1 second and then the first message appears. Both the functions are being called at once as they are asynchronous. Is there any way to pipeline them?

setTimout() is not blocking in Javascript. So, what you did is you scheduled two timers to run in the future. One runs 1 second from now . The other runs two seconds from now . Thus, you get the behavior you observed.

You can either schedule the first one to run 2 seconds from now and then for one to go 1 second after that, you schedule it for 3 seconds from now.

setTimeout(function(){
    process.stdout.write('\n\nJokes Apart !!!\n\n');
}, 2000);

// schedule this one to be 3 seconds from now, which will be 1 second after the prior one
// since that one fired in 2 seconds
setTimeout(function(){
    process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 3000);

Or, you can schedule the first one to run 2 seconds from now and then in that callback, you then schedule the next one to run 1 second from when the first one fires.

setTimeout(function(){
    process.stdout.write('\n\nJokes Apart !!!\n\n');
        // when the first timer fires, set a new timer to run the second
        // part one second from when the first one fired
        setTimeout(function(){
            process.stdout.write('\n\nLet\'s play a game !!!\n\n');
        }, 1000);
}, 2000);

This non-blocking characteristic is what gives Javascript it's asynchronous behavior. When you call the first setTimeout() , the Javascript interpreter doesn't just stop and wait for the timer to fire. Instead, it schedules that timer to run sometime in the future and then it keeps on executing the rest of your Javascript. In your code, the next line of code is another setTimeout() so it immediately schedules that timer too. Since they were both scheduled at the same time, it makes sense that the one scheduled for 2 seconds from now comes after the one scheduled for 1 second from now.

Thus, you end up with two choices. You can either change the time on the second time to make it fire when you want it to fire (given that the code to schedule both timers is run at basically the same time) or you can change when you schedule the second timer until after the first timer has fired.

To understand what's happening, you should first understand the JS event loop and its non-blocking nature. You can read about it here: https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/ , or if you prefer video form, this is a great talk: https://youtu.be/8aGhZQkoFbQ

In a nutshell, the engine goes through the code - when it encounters the first setTimeout , it schedules it (for 2 seconds later), and keeps going . It then sees the second setTimeout and schedules it as well. When a second passes, the callback from the second setTimeout is triggered and executed, and only a second later, the callback from the first one is triggered. This is why you see them in that order.

Now to fixing it - all you need to do is just nest them:

setTimeout(function(){
   process.stdout.write('\n\nJokes Apart !!!\n\n');

   setTimeout(function(){
       process.stdout.write('\n\nLet\'s play a game !!!\n\n');
   }, 1000);
}, 2000);

This causes the second setTimeout to get scheduled only when the callback from the first one is run.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM