NodeJS - setTimeout(fn,0) vs setImmediate(fn)

Solution 1:

setTimeout is simply like calling the function after delay has finished. Whenever a function is called it is not executed immediately, but queued so that it is executed after all the executing and currently queued eventhandlers finish first. setTimeout(,0) essentially means execute after all current functions in the present queue get executed. No guarantees can be made about how long it could take.

setImmediate is similar in this regard except that it doesn't use queue of functions. It checks queue of I/O eventhandlers. If all I/O events in the current snapshot are processed, it executes the callback. It queues them immediately after the last I/O handler somewhat like process.nextTick. So it is faster.

Also (setTimeout,0) will be slow because it will check the timer at least once before executing. At times it can be twice as slow. Here is a benchmark.

var Suite = require('benchmark').Suite
var fs = require('fs')

var suite = new Suite

suite.add('deffered.resolve()', function(deferred) {
  deferred.resolve()
}, {defer: true})

suite.add('setImmediate()', function(deferred) {
  setImmediate(function() {
    deferred.resolve()
  })
}, {defer: true})

suite.add('setTimeout(,0)', function(deferred) {
  setTimeout(function() {
    deferred.resolve()
  },0)
}, {defer: true})

suite
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})

Output

deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)

First one gives idea of fastest possible calls. You can check yourself if setTimeout gets called half as many times as other. Also remember setImmediate will adjust to your filesystem calls. So under load it will perform less. I don't think setTimeout can do better.

setTimeout is un-intrusive way of calling functions after some time. Its just like its in the browser. It may not be suited for server-side (think why I used benchmark.js not setTimeout).

Solution 2:

A great article about how event loop works and clears some misconceptions. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Citing the article:

setImmediate callbacks are called after I/O Queue callbacks are finished or timed out. setImmediate callbacks are placed in Check Queue, which are processed after I/O Queue.

setTimeout(fn, 0) callbacks are placed in Timer Queue and will be called after I/O callbacks as well as Check Queue callbacks. As event loop, process the timer queue first in each iteration, so which one will be executed first depends on which phase event loop is.

Solution 3:

setImmediate() is to schedule the immediate execution of callback after I/O events callbacks and before setTimeout and setInterval .

setTimeout() is to schedule execution of a one-time callback after delay milliseconds.

This is what the documents say.

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

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

If you run the above code, the result will be like this... even though the current doc states that "To schedule the "immediate" execution of callback after I/O events callbacks and before setTimeout and setInterval." ..

Result..

setTimeout

setImmediate

If you wrap your example in another timer, it always prints setImmediate followed by setTimeout.

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

Solution 4:

always use setImmediate, unless you are really sure that you need setTimeout(,0) (but I can't even imagine, what for). setImmediate callback will almost always be executed before setTimeout(,0), except when called in first tick and in setImmediate callback.

Solution 5:

setTimeout(fn,0) can be used for preventing the browser from freezing in massive update. for example in websocket.onmessage, you may have html changes, and if messages keep coming, the browser may freeze when using setImmidiate