#541·q

Q uses process.nextTick instead of setImmediate in Node 0.10.x

Author: joe-spanningCreated Jun 18, 2014Updated Dec 14, 2017

I am using Q 1.0.1 and Node.js 0.10.24

I have a application that uses Q to recursively process large amounts of data using the following pattern:

javascript
doPromiseyThing()
  .then(function(result) {
    if (moreToDo) {
      return doPromiseyThing();
    }

    return result;
  });

If there is a large amount of data to process in this way, I eventually get the error:

Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.

node.js:375
        throw new Error(msg);
              ^
Error: (node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.
    at maxTickWarn (node.js:375:15)
    at process.nextTick (node.js:480:9)
    at onwrite (_stream_writable.js:260:15)
    at WritableState.onwrite (_stream_writable.js:97:5)
    at Socket._write (net.js:651:5)
    at doWrite (_stream_writable.js:221:10)
    at writeOrBuffer (_stream_writable.js:211:5)
    at Socket.Writable.write (_stream_writable.js:180:11)
    at Socket.write (net.js:613:40)
    at Console.warn (console.js:61:16)

This error is not caught by my fail handler function, so I cannot recover from it. It comes across as an uncaught exception in Node. However, this is not the point of me creating the ticket.

The error states that setImmediate should be used instead of process.nextTick. Looking at the source of q.js lines 158 - 177:

javascript
if (typeof process !== "undefined" && process.nextTick) {
        // Node.js before 0.9. Note that some fake-Node environments, like the
        // Mocha test runner, introduce a `process` global without a `nextTick`.
        isNodeJS = true;

        requestTick = function () {
            process.nextTick(flush);
        };

    } else if (typeof setImmediate === "function") {
        // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
        if (typeof window !== "undefined") {
            requestTick = setImmediate.bind(window, flush);
        } else {
            requestTick = function () {
                setImmediate(flush);
            };
        }

    }

It prefers process.nextTick to setImmediate.

If would be nice if this code was changed to use setImmediate, or if I could configure Q to prefer setImmediate over process.nextTick via an environment variable.