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.