1

How often, or when, should I use process.nextTick?

I understand the purpose of it (mainly because of this and this).

As rule of thumb, I'm always using it when I have to call a callback. Is this the general approach or there is more to it?

Also, on here:

It is very important for APIs to be either 100% synchronous or 100% asynchronous.

Being 100% synchronous simply means never using process.nextTick and 100% asynchronous always using it?

Community
  • 1
  • 1
talles
  • 14,356
  • 8
  • 45
  • 58
  • I don't know enough about Node (and `nextTick` in particular) to give a good, full answer, however: it's not quite right to say "always use `nextTick`". That link seems to say "use `nextTick` whenever you need to match the behavior of other asynchronous APIs that your function uses". That is, if your function uses an API that forces it to be asynchronous sometimes, it should also be async (via `nextTick`) even in cases where it doesn't require that async API. – apsillers Nov 01 '13 at 16:17
  • what's wrong with setTimeout? – dandavis Nov 01 '13 at 16:18
  • @dandavis The only things I can gather from link are 1) `setTimeout(fn, 0)` is apparently "less efficient" and 2) `nextTick` gives your function higher priority over any pending async I/O. (Maybe that's what they mean by "more efficient"?) – apsillers Nov 01 '13 at 16:20
  • node is fast enough, i would error on the side of portability and allowing common V8 user-land optimizations. just sayin' we don't really need nextTick()... – dandavis Nov 01 '13 at 16:24
  • @dandavis: `setTimeout(..., 0)` introduces a latency of 6-12ms before the function is invoked. Throw a few of those in, and something that should take < 1ms now takes 100. `nextTick` invokes the function within microseconds. It is important, and saying "just use `setTimeout`" is bad advice. – josh3736 Nov 01 '13 at 18:21
  • i still think that setTimeout gives more flexibility to V8 on how/when the code is executed, which might lead to an over-all increase in performance. if you interrupt IO, you slow down other tasks. even if the particular transaction in question takes a hair longer, the CPU time of your app will likely be higher using nextTick than setTimeout. if a particular routine needs that extra 5ms, then go for it if you feel the need. it's a tradeoff, like everything in programming. for general callbacks, i don't see a need for such explicit interruption. – dandavis Nov 01 '13 at 18:46
  • @dandavis: `setTimeout` doesn't "give V8 more flexibility": it actually requires more resources than `nextTick`. `setTimeout` **always** requires node to go to libuv (C++) and set up a timer *at least* 1ms in the future, which is non-trivial overhead. `nextTick` is handled totally in JS-land. **You *will not* improve performance by using `setTimeout` where you should use `nextTick`.** – josh3736 Nov 01 '13 at 20:29

1 Answers1

1

Consider the following:

// API:
function foo(bar, cb) {
    if (bar) cb();
    else {
        process.nextTick(cb);
    }
}

// User code:
function A(bar) {
    var i;
    foo(bar, function() {
        console.log(i);
    });
    i = 1;
}

Calling A(true) prints undefined, while calling A(false) prints 1.

This is a somewhat contrived example – obviously it's a little silly to assign to i after we make the async call – but there are real-world scenarios where invoking callback code before the remainder of the calling code can complete might result in subtle bugs.

Thus the recommendation to use nextTick when you'd otherwise invoke the callback synchronously. Basically, any time you call the user callback in the same stack that your function was called (in other words, if you call the user callback outside of a callback function of your own), use nextTick.

Here's a more concrete example:

// API
var cache;

exports.getData = function(cb) {
    if (cache) process.nextTick(function() {
        cb(null, cache); // Here we must use `nextTick` because calling `cb`
                         // directly would mean that the callback code would
                         // run BEFORE the rest of the caller's code runs.
    });
    else db.query(..., function(err, result) {
        if (err) return cb(err);

        cache = result;
        cb(null, result); // Here it it safe to call `cb` directly because
                          // the db query itself is async; there's no need
                          // to use `nextTick`.
    });
};
josh3736
  • 139,160
  • 33
  • 216
  • 263
  • "Basically, any time you call the user callback in the same stack that your function was called (in other words, if you call the user callback outside of a callback function of your own), use nextTick.". That is what I wanted to confirm :) – talles Nov 01 '13 at 19:07