41

NodeJS 0.11 as well as io.js and the Node 0.12 branch all ship with native promises.

Native promises have a .then method which always executes on a future event loop cycle.

So far I've been using setImmediate to queue things to the next iteration of the event loop ever since I switched from nextTick:

setImmediate(deferThisToNextTick); // My NodeJS 0.10 code
process.nextTick(deferThisToNextTick); // My NodeJS 0.8 code

Since we now have a new way to do this:

Promise.resolve().then(deferThisToNextTick); 

Which should I use? Also - does Promise.resolve.then act like setImmediate or like nextTick with regards to code running before or after the event loop?

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Sharing some research: In Chromium - a promise enqueues a microtask, here's run microtask https://github.com/yoavweiss/Blink/blob/80ec93f1d58a0a0ce99a07ed07c203a106b2a88c/Source/core/dom/Microtask.cpp called here when a script arrives or checked and no script is running: https://github.com/yoavweiss/Blink/blob/5be896b969d644c18facc30833210b07f43ae086/Source/core/html/parser/HTMLScriptRunner.cpp – Benjamin Gruenbaum Dec 25 '14 at 13:53
  • Promise resolution https://github.com/joyent/node/blob/857975d5e7e0d7bf38577db0478d9e5ede79922e/deps/v8/src/promise.js#L154 - calls https://github.com/joyent/node/blob/857975d5e7e0d7bf38577db0478d9e5ede79922e/deps/v8/src/execution.cc#L321 - gets to https://github.com/joyent/node/blob/857975d5e7e0d7bf38577db0478d9e5ede79922e/deps/v8/src/execution.cc#L310 – Benjamin Gruenbaum Dec 25 '14 at 14:01
  • 2
    Very related: https://github.com/joyent/node/issues/7714 – Benjamin Gruenbaum Dec 25 '14 at 14:05
  • More sauce: https://github.com/joyent/node/blob/v0.12/src/node.js#L305 – Benjamin Gruenbaum Dec 25 '14 at 14:16
  • Verified microtasks run on the nextTick queue: https://github.com/joyent/node/blob/v0.12/src/node.js#L326-L329 , going to wait a few hours to see if a v8 or node team member feels like clarifying and if not I'll write my answer. – Benjamin Gruenbaum Dec 25 '14 at 14:19
  • You can share this question in that github discussion, so that they might come here and answer. – thefourtheye Dec 25 '14 at 14:26

3 Answers3

36

Using Promise.resolve().then has no advantages over nextTick. It runs on the same queue, but have slightly higher priority, that is, promise handler can prevent next tick callback from ever running, the opposite is not possible. This behaviour is an implementation detail and should not be relied on.

Promise.resolve().then is obviously slower (a lot, I think), because it creates two promises which will be thrown away.

You can find extensive implementation info here: https://github.com/joyent/node/pull/8325

The most important part: Promise.resolve().then is like nextTick and not like setImmediate. Using it n place of setImmediate can change your code behaviour drastically.

vkurchatkin
  • 13,364
  • 2
  • 47
  • 55
  • 1
    Upvoted. I would love to see an example for the last paragraph. – thefourtheye Dec 25 '14 at 15:22
  • Thanks this sounds correct and what I've observed at the code too. It would be nice if you could elaborate on when to use either and why it works this way. @thefourtheye any example of where `nextTick` wouldn't work instead of `setImmediate` - neither would `Promise.resolve().then` – Benjamin Gruenbaum Dec 25 '14 at 15:27
  • What I mean is you should not use `Promise.resolve().then` at all. This trick achieves nothing. Regarding nextTick vs setImmediate there is a lot of info – vkurchatkin Dec 25 '14 at 15:55
  • 1
    "It runs on the same queue, but have slightly higher priority..." Actually, not really. Each one has its own mechanism to handle the queue of callbacks. – Trevor Norris Dec 30 '14 at 19:00
  • Well, microtask queue is flushed inside `nextTick` queue, that's what I meant. The intention was to make this behave as one queue as much as possible – vkurchatkin Dec 31 '14 at 05:34
  • @vkurchatkin why does this create two promises? "Promise.resolve().then is obviously slower (a lot, I think), because it creates two promises which will be thrown away" ? – human Apr 15 '20 at 23:31
  • Promise.resolve() creates the first one, .then() creates the second one – vkurchatkin Apr 16 '20 at 13:47
10

I'm not going to answer the bolded part about technicalities, but only the question

Which should I use?

I don't think there is any reason to use Promise.resolve().then() unless you are interested in the promise for the result of your asynchronously executed function. Of course, if you are, then this would be far superior than dealing with callback hell or making a new Promise from setTimeout or nextTick.

There's also a second technical difference, more import than the timing: promises do swallow exceptions. Which you probably don't want. So, like @vkurchatkin mentioned, don't create promises only to throw them away. Not only because it's slower, but because it makes your code less readable and your app more error-prone.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
-5

Promise.resolve would be resolved straight away (syncroniously), while setImmediate explicitly straight after the execution of current event.

Ilia Sidorenko
  • 2,157
  • 3
  • 26
  • 30
  • 2
    Try this in your browser console to see you're wrong: `Promise.resolve([]).then(function(){ console.log('1'); }); console.log('2');` – Martin Konecny Nov 01 '17 at 15:26
  • I think you are confusing it with new `Promise((res, rej) => res());`. The above example `new Promise((res) => { console.log(1); res(); }); console.log(2);`. In that case `1` will get printed before `2`. – Trenskow Jul 06 '20 at 19:33