metis metis - 5 months ago 30
Node.js Question

setImmediate() function is called after setTimeout() function

In the official sites of nodejs (https://nodejs.org/api/timers.html#timers_setimmediate_callback_arg), it is said that :


setImmediate() function schedules "immediate" execution of callback
after I/O events' callbacks and before timers set by setTimeout and
setInterval are triggered.


However in the below code, setTimeout() function executed before setImmediate(). Why?

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

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


Result:


TIMEOUT FIRED
1
4
2
3
5
6


I write another example, and
setTimeout
works before
setImmediate
here too.

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

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

setImmediate(function D() { console.log(1); });
setImmediate(function D() { console.log(2); });
setImmediate(function D() { console.log(3); });

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

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


Output:


TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
1
2
3

Answer

Lets write the above example as following :

var fs = require('fs')

fs.readFile("readme.txt",  function (){
    setTimeout(function timeout() {
      console.log('TIMEOUT-1 FIRED');
    }, 0)

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

    setImmediate(function D() { console.log(1); });
    setImmediate(function D() { console.log(2); });
    setImmediate(function D() { console.log(3); });

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

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

Output :

1
2
3
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED

Explanation :

The order in which the timers are executed will vary depending on the context in which they are called. If both are called from within the main module, then timing will be bound by the performance of the process (which can be impacted by other applications running on the machine). For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process:

// timeout_vs_immediate.js
setTimeout(function timeout () {
  console.log('timeout');
},0);

setImmediate(function immediate () {
  console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate

$ node timeout_vs_immediate.js
immediate
timeout

However, if you move the two calls within an I/O cycle, the immediate callback is always executed first:

// timeout_vs_immediate.js
var fs = require('fs')

fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  setImmediate(() => {
    console.log('immediate')
  })
})
$ node timeout_vs_immediate.js
immediate
timeout

$ node timeout_vs_immediate.js
immediate
timeout

The main advantage to using setImmediate() over setTimeout() is setImmediate() will always be executed before any timers if scheduled within an I/O cycle, independently of how many timers are present.

For more info, refer the following link : https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md

Comments