How are node Promises getting in between `nextTick

2019-02-14 16:46发布

问题:

I had a weird timing bug in my app that came from switching from Bluebird to native promises. I fixed it, but am left with this oddity: Native promises seem to wiggle their way in between nextTick and setImmediate -- how? And is this supposed to happen? Where are promises supposed to go with regard to these?

~function(){
  setTimeout            (console.log.bind(console, 'timeout A'));
  process.nextTick      (console.log.bind(console, 'nextTick A'));
  setImmediate          (console.log.bind(console, 'setImmediate A'));
  Promise.resolve().then(console.log.bind(console, 'promise'));
  process.nextTick      (console.log.bind(console, 'nextTick B'));
  setImmediate          (console.log.bind(console, 'setImmediate B'));
  setTimeout            (console.log.bind(console, 'timeout B'));
}();

Native yields:

nextTick A
nextTick B
promise undefined
setImmediate A
setImmediate B
timeout A
timeout B

Bluebird yields:

nextTick A
nextTick B
setImmediate A
promise undefined
setImmediate B
timeout A
timeout B

回答1:

Native promises seem to wiggle their way in between nextTick and setImmediate -- how? And is this supposed to happen? Where are promises supposed to go with regard to these?

Yes, promises run after the microtask nextTick queue and before any tasks (like setImmediate) execute.

This is their intended behavior, and what we expect them to do in NodeJS. This was decided here and you can read about it here

Bluebird's different behavior

Bluebird's behavior predates native promises, bluebird 3.0 uses nextTick and microtask semantics for scheduling. Bluebird lets you manually override this behavior using Promise.setScheduler with nextTick as the scheduler (instead of setImmediate).

You can see the code here:

GlobalSetImmediate.call(global, fn)

NOTE THAT YOUR CODE SHOULD NOT RELY ON THESE BEHAVIORS ANYWAY.