Skip to content

Instantly share code, notes, and snippets.

Last active February 23, 2020 22:35
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
process.nextTick vs setImmediate

@mafintosh asks: "Does anyone have a good code example of when to use setImmediate instead of nextTick?"

The answer is "generally anywhere outside of core".

process.nextTick is barely asynchronous. Flow-wise it is asynchronous, but it will trigger before any other asynchronous events can (timers, io, etc.) and thus can starve the event loop.

In this script I show a starved event loop where I just synchronously block, use nextTick and setImmediate

bryce@x1c:~/tmp$ /usr/bin/time node starved.js blocked
I took 1608.396358ms, expected to take 10
1.68user 0.00system 0:01.69elapsed 99%CPU (0avgtext+0avgdata 24016maxresident)k
0inputs+0outputs (0major+3572minor)pagefaults 0swaps
bryce@x1c:~/tmp$ /usr/bin/time node starved.js nexttick
I took 1611.755809ms, expected to take 10
1.68user 0.00system 0:01.70elapsed 99%CPU (0avgtext+0avgdata 24024maxresident)k
0inputs+0outputs (0major+3572minor)pagefaults 0swaps
bryce@x1c:~/tmp$ /usr/bin/time node starved.js setimmediate
I took 144.870217ms, expected to take 10
1.68user 0.00system 0:01.69elapsed 99%CPU (0avgtext+0avgdata 23952maxresident)k
0inputs+0outputs (0major+3578minor)pagefaults 0swaps

Notice the blocked and nexttick behave the same -- the setTimeout is delayed until after all calls to the blocking run function.

Even though we're scheduling more process.nextTick calls asynchronously, nothing can get inserted between them on the event loop.

The setImmediate example is not blocked as long because the setTimeout gets run between consecutive setImmediate calls, and even though it is late (the run function is slow enough to delay it on its own) it still gets through.

var loops = 11
function run() {
for (var i = 0; i < 1e7; i++) {
Math.pow(Math.random(), Math.random())
if (loops > 0) {
if (process.argv[2] == "blocked") {
if (process.argv[2] == "nexttick") {
if (process.argv[2] == "setimmediate") {
var delay = 10
var start = process.hrtime()
setTimeout(function () {
var elapsed = process.hrtime(start)
var ms_elapsed = (elapsed[0] * 1000) + (elapsed[1] / 1e6)
console.log("I took %sms, expected to take %s", ms_elapsed, delay)
}, delay)
Copy link

ackuser commented Jan 3, 2016

var emitter = new require('events').EventEmitter();

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

setImmediate(function() {
    console.log("IMMEDIATE 1");

process.nextTick(function() {
    console.log("NEXTTICK 1");

setTimeout(function() {
  setTimeout(function() {
    console.log('TIMEOUT 2')
  }, 0);
  setImmediate(function() {
    console.log('IMMEDIATE 2')
}, 10);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment