0

The docs for Promise.all() describe the argument as an array of Promises. Is behavior defined if some (or all) of the elements in the array are non-Promise values? For example, in Node 6.10.2:

Promise.all([1, 2, 3]).then(
  res => console.log(res)
);

Prints [ 1, 2, 3 ], as expected. Is this behavior (where Promise.all resolves with the same values that it was called with) guaranteed in Node?

FeifanZ
  • 16,250
  • 7
  • 45
  • 84
  • 1
    From my little bit of googling it looks like [`Promise.all` is defined in the ECMAScript standard](http://www.ecma-international.org/ecma-262/6.0/#sec-promise.all). – zzzzBov May 10 '17 at 00:00
  • 1
    [Yup](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all#Using_Promise.all) – aaaaaa May 10 '17 at 00:00
  • Thanks @zzzzBov and `aaaaaa` — happy to accept an answer if you want to post one :) – FeifanZ May 10 '17 at 00:16
  • @zzzzBov - Can you tell in that spec 25.4.4.1 where the OP's question is actually answered? – jfriend00 May 10 '17 at 00:18
  • @jfriend00, didn't have time to dig in and actually read the spec, just had an inkling of where the info might be. – zzzzBov May 10 '17 at 00:19
  • possible duplicate of [Are there promise standards for extended functions like .all(), etc](http://stackoverflow.com/q/27283401/1048572)? – Bergi May 10 '17 at 00:24
  • `Promise.all` never resolves with the same value that it was called with, it always creates a new array. – Bergi May 10 '17 at 00:25

1 Answers1

5

Promise.all() is specified in the ES6 specification.

It appears that section 24.4.4.1.1 in that ES6 specification at step 6.i describes how each item in the iterable passed to Promise.all() is passed to a promise constructor (essentially calling Promise.resolve(item)) so that any non-promise gets wrapped in a promise that will resolve itself on the next tick.

You need to follow the overall context of how these steps work to fully understand, but the specific 6.i step is this:

Let nextPromise be Invoke(constructor, "resolve", «‍nextValue»).

Where constructor (in this context) is Promise and Invoke() is calling the resolve method on it - so it's essentially doing:

let nextPromise = Promise.resolve(nextValue);

Which is how each item in the iterable is wrapped in a promise if it wasn't already a promise.

Then, later in step 6.r, it does this:

Let result be Invoke(nextPromise, "then", «‍resolveElement, resultCapability.[[Reject]]»).

Which is where it calls .then() on nextPromise which will now work fine even if the item in the iterable was not originally a promise because it has been wrapped in a new promise.

And, in 24.4.4.5 the description of Promise.resolve(x) is as follows:

The resolve function returns either a new promise resolved with the passed argument, or the argument itself if the argument is a promise produced by this constructor.

So, you can see that the value is wrapped in a new promise if it is not already a promise.


Is this behavior (where Promise.all() resolves with the same values that it was called with) guaranteed in Node?

Yes, if the values are not promises, then it will resolve with an array of the same values. It will be a different array, but the same values in the new array. If any of the values are promises, then obviously, the final array contains the resolved value of that promise. This is guaranteed by the specification.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I noticed that in the spec as well — it seemed to be wrapping iterator values in a Promise, but I wasn't completely sure that's what it says the first time I read it. Thanks for clarifying! – FeifanZ May 10 '17 at 17:58