4

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
  • I don't think there's a definitive answer. Apparently, their timing is done by approaching the event loop via *native* code (while Bluebird uses `setImmediate`). I don't think there's any spec telling us what shall happen, the implementation (node V8) is free to do what it deems reasonable. – Bergi Sep 08 '15 at 11:52
  • @Bergi - Considering that `nextTick` and `setImmediate` are node constructs and not part of v8, I believe node should define this in a reliable manner. –  Sep 08 '15 at 12:11
  • Actually `setImmediate` is available in browser as well and there's a draft to incorporate it into the HTML5 spec iirc. But yes, it's node that needs to and does define it, so it is "supposed" to work just like it does. There might be some docs for node about this, is that what you are looking for? – Bergi Sep 08 '15 at 13:24
  • @Bergi well, the DOM specification _dictates_ that promises run with microtask semantics. Node had to make a choice about it and chose microtask semantics. setImmediate does something different in node and the browser by the way. There are no docs really, and there are maybe 10-20 people who know and care about it :) If you think it's worth documenting a pull request would be nice. – Benjamin Gruenbaum Sep 08 '15 at 16:12
  • @BenjaminGruenbaum - A conversation on github seems to imply that node didn't make any choice, and that it's v8 using microtasks. Is there any documentation on this? –  Sep 08 '15 at 17:12
  • @BenjaminGruenbaum: Ah, I did not look at the DOM spec for long, references to microtasks and promise jobs are new to me. Do you have a link at hand? – Bergi Sep 08 '15 at 17:49

1 Answers1

3

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.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504