94

I'm very confused about the differences between nextTick and setImmediate. I've read all the documentation about them on the internet but I still don't understand how they work.

Examples:

function log(n) { console.log(n); }

setImmediate

setImmediate(function() {
  setImmediate(function() {
    log(1);
    setImmediate(function() { log(2); });
    setImmediate(function() { log(3); });
  });
  setImmediate(function() {
    log(4);
    setImmediate(function() { log(5); });
    setImmediate(function() { log(6); });
  });
});

//1 2 3 4 5 6

nextTick

process.nextTick(function() {
  process.nextTick(function() {
    log(1);
    process.nextTick(function() { log(2); });
    process.nextTick(function() { log(3); });
  });
  process.nextTick(function() {
    log(4);
    process.nextTick(function() { log(5); });
    process.nextTick(function() { log(6); });
  });
});

//1 4 2 3 5 6

Why these results? Please explain with a visual or very easy to follow explanation. Even the node core devs don't agree at how nextTick and setImmediate should be understood by people.

Sources:

Community
  • 1
  • 1
Gabriel Llamas
  • 18,244
  • 26
  • 87
  • 112

5 Answers5

107

Consider the following two examples:

setImmediate

setImmediate(function A() {
  setImmediate(function B() {
    log(1);
    setImmediate(function D() { log(2); });
    setImmediate(function E() { log(3); });
  });
  setImmediate(function C() {
    log(4);
    setImmediate(function F() { log(5); });
    setImmediate(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6

nextTick

process.nextTick(function A() {
  process.nextTick(function B() {
    log(1);
    process.nextTick(function D() { log(2); });
    process.nextTick(function E() { log(3); });
  });
  process.nextTick(function C() {
    log(4);
    process.nextTick(function F() { log(5); });
    process.nextTick(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 1 4 2 3 5 6 'TIMEOUT FIRED'

setImmediate callbacks are fired off the event loop, once per iteration in the order that they were queued. So on the first iteration of the event loop, callback A is fired. Then on the second iteration of the event loop, callback B is fired, then on the third iteration of the event loop callback C is fired, etc. This prevents the event loop from being blocked and allows other I/O or timer callbacks to be called in the mean time (as is the case of the 0ms timeout, which is fired on the 1st or 2nd loop iteration).

nextTick callbacks, however, are always fired immediately after the current code is done executing and BEFORE going back to the event loop. In the nextTick example, we end up executing all the nextTick callbacks before ever returning to the event loop. Since setTimeout's callback will be called from the event loop, the text 'TIMEOUT FIRED' will not be output until we're done with every nextTick callback.

Dave Stibrany
  • 2,369
  • 3
  • 21
  • 21
  • 8
    Perfect, the last paragraph is the key to understand the main difference. – Gabriel Llamas Nov 30 '13 at 11:47
  • your nextTick example has different output: `TIMEOUT FIRED 1 4 2 3 5 6` – Jürgen Paul Mar 13 '14 at 22:54
  • What version of node are you running? On node 0.10.x you should always have your nextTick callbacks run before hitting the event loop. – Dave Stibrany Mar 14 '14 at 00:22
  • 24
    I wish they would have chosen a different name. Right now "nextTick" is more immediate than setImmediate. – Jelle De Loecker Jul 30 '14 at 21:50
  • Do you have an example with relation to I/O? – Jürgen Paul Dec 06 '14 at 01:19
  • frankly if process.nextTick doesn't go back out to the event loop then wtf is the point of it. If I wanted to call a function next I would just call it explicitly by name. No wonder, process.nextTick is being deprecated. I always thought process.nextTick functioned like setImmediate actually does. process.nextTick is then a huge misnomer. – Alexander Mills May 18 '15 at 22:58
  • I'm know what you mean. There's an example in the docs that explains a possible use case. https://nodejs.org/api/process.html#process_process_nexttick_callback – Dave Stibrany May 19 '15 at 04:36
  • @DaveStibrany .. sorry to bug you after a long time . I am a newbie to node.js. Just to clarify why A, then B,then C,then D and E and then F and G callbacks were called in order ? Why not A,B,D,E,C,F,G ? – StrugglingCoder Dec 13 '15 at 20:48
  • 1
    @StrugglingCoder Because when A executes, it sets B and C to be scheduled next. When B executes it sets D and E to be scheduled next, but C has already been scheduled for after B. Remember that there is a difference between when the callback is scheduled or registered and when the callback actually fires. – Dave Stibrany Dec 14 '15 at 19:46
  • @DaveStibrany in `setImmediate ` I think B and C are pushed to `check queue` in same iteration because JS is `run to complete` – Guichi Sep 09 '16 at 10:00
  • Yes **@Guichi** You are absolutely right. B and C scheduled at the time of A() Callaback execution. – vigneshRavi Dec 02 '19 at 19:11
25

According the Node.js doc names of these two function are exactly swapped

setImmediate() (BEST RECOMMENDED)

It's fire first at event queue


process.nextTick() (USE FOR SPECIAL CASES see example later on)

It's fire immediately, It's kinda write an statement more at the end at the current file


If we have this code

setTimeout(function(){
  console.log('Hello world 5'); // It's waiting like a normal person at a queue
}, 0);

setImmediate(function(){
  console.log('Hello world 4'); 
  // It's like get to last and be take care of first 
  // but always after of .nextTick and before of setInterval(, 0)
});

process.nextTick(function(){
   console.log('Hello world 3'); // It's like be at the bottom at this file
});

console.log('Hello world 1');
console.log('Hello world 2');

A visual explanation as per your request:

enter image description here

Cases for use process.nextTick() when you have to emit and event before to handled it:

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);

  // use nextTick to emit the event once a handler is assigned
  process.nextTick(function () {
    this.emit('event');
  }.bind(this));
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
  console.log('an event occurred!');
});

Look at this vide where Philip Roberts give us a great explanation about runtime event loop and look at this online eventloop debugger Live test how event loop works

Source: https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate

gsalgadotoledo
  • 2,666
  • 1
  • 25
  • 22
  • if you run the first snippet, it does not behave as you mentioned - Hello world 1 Hello world 2 Hello world 3 Hello world 5 Hello world 4 – Abhishek Chandel Feb 12 '23 at 12:13
8

I can't reproduce your results for setImmediate. It should be the same as nextTick (and it is in my tests) since in this situation they do pretty much the same thing. The only reasonable explanation for that is that setImmediate is somehow synchronous, but it is not.

And according to NodeJS documentation the only real difference is that multiple nextTick may fire in one loop iteration (depending on maxTickDepth), while setImmediate fires once per iteration.

freakish
  • 54,167
  • 9
  • 132
  • 169
6

Below gives you better clarity.

setImmediate

  1. It's execute a script once the current poll phase completes.
  2. It's a timer module function and timer functions are global, you can call them without require.
  3. It can cleared by clearImmediate().
  4. Set "immediate" execution of the callback after I/O events' callbacks before setTimeout() and setInterval().

nextTick

  1. It's a process global object function of NodeJS.
  2. All callbacks passed to process.nextTick() will be resolved before the event loop continues.
  3. Allow users to handle errors.
  4. Helps to try the request again before the event loop continues.

Simple code Snippet.

console.log("I'm First");

setImmediate(function () {
  console.log('Im setImmediate');
});

console.log("I'm Second");

process.nextTick(function () {
  console.log('Im nextTick');
});

console.log("I'm Last");

/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/
Venkat.R
  • 7,420
  • 5
  • 42
  • 63
2

I think all the answers above are obsolete, because I got different answers constantly with the current version of nodejs and it is easy to reason about

var log=console.log
log(process.version)

var makeAsyncCall
if(false)
    makeAsyncCall=setImmediate
else
    makeAsyncCall=process.nextTick;

makeAsyncCall(function A () {
    makeAsyncCall(function B() {
        log(1);
        makeAsyncCall(function C() { log(2); });
        makeAsyncCall(function D() { log(3); });
    });
    makeAsyncCall(function E() {
        log(4);
        makeAsyncCall(function F() { log(5); });
        makeAsyncCall(function G() { log(6); });
    });
});
//1
//4
//2
//3
//5
//6
//in both case

After reading https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate let use start from setImmediate we should keep track of the check queue because it is where the setImmediate callback reside.

First iteration

A is push to check queue

check queue :[A]

Second iteration

A is pull out from queue to execute

During its execution ,it put B and E to queueand then, A complete and start next iteration

check queue :[B,E]

Third iteration

pull out B and push C D

check queue :[E,C,D]

Forth iteration

pull out E and push F G

check queue : [C,D,F,G]

Finally

execute the callbacks in the queue sequentially

For nextTick case, the queue works exactly the same way,that is why it produce same result

The different is that :

the nextTickQueue will be processed after the current operation completes, regardless of the current phase of the event loop

To be clear,the event loop maintain multiple queues and check queue is just one of them,the node will decide which queue to use based on some rules

with process.nextTick however,it is sort of bypassing all the rule and execute the callback in nextTick immediately

Guichi
  • 2,150
  • 1
  • 19
  • 27