I would like to execute a set of promises using Promise.all(). My approach is to put these promises in an array and then pass the array to Promise.all(). However, I find that the promises start executing as soon as they are declared and do not even wait for Promise.all to be called.
Why is this happening and how can I have the promises only execute upon calling Promise.all()?
let promiseArray = [];
const values = [1, 2, 3, 4, 5];
values.forEach((value)=>{
promiseArray.push(
new Promise((resolve, reject)=>{
console.log('value: ' + value);
return resolve();
})
)
})
console.log('start')
Promise.all(promiseArray)
/*
output is
value: 1
value: 2
value: 3
value: 4
value: 5
start
would have expected output to have been
start
value: 1
value: 2
value: 3
value: 4
value: 5
*/
I would like to execute a set of promises using Promise.all(). My approach is to put these promises in an array and then pass the array to Promise.all(). However, I find that the promises start executing as soon as they are declared and do not even wait for Promise.all to be called.
Why is this happening and how can I have the promises only execute upon calling Promise.all()?
let promiseArray = [];
const values = [1, 2, 3, 4, 5];
values.forEach((value)=>{
promiseArray.push(
new Promise((resolve, reject)=>{
console.log('value: ' + value);
return resolve();
})
)
})
console.log('start')
Promise.all(promiseArray)
/*
output is
value: 1
value: 2
value: 3
value: 4
value: 5
start
would have expected output to have been
start
value: 1
value: 2
value: 3
value: 4
value: 5
*/
Share
Improve this question
asked Apr 6, 2018 at 5:13
takinolatakinola
1,7731 gold badge13 silver badges27 bronze badges
3
- 3 that is how they are designed to work - the Promise executor is executed immediately and synchronously ... there is no simple answer as to why. – Jaromanda X Commented Apr 6, 2018 at 5:17
-
if you want the code to behave as you expect, simple change to one line ...
promiseArray.push(() =>
and thenPromise.all(promiseArray.map(fn => fn()))
– Jaromanda X Commented Apr 6, 2018 at 5:23 - 2 Your intuition is actually reasonable. The design decision to eagerly execute the Promises constructor is at least questionable. – user6445533 Commented Apr 6, 2018 at 18:26
2 Answers
Reset to default 15Thinking of promises as "executing" is getting you confused. A promise is purely a notification mechanism. It is typically tied to some underlying asynchronous operation and when you create the promise, the asynchronous operation is typically started.
Promise.all()
is then used to track when a whole bunch of asynchronous operations that you've already started have pleted (or ended with an error).
So, you don't use Promise.all()
to start a bunch of things. You use it just to track when they are all done and they are started elsewhere in your code.
When you manually create a promise with new Promise()
, the promise executor is executed immediately. That's how they are designed.
If you had real asynchronous operations in your promise executor and you were doing console.log()
when those operations pleted, you'd probably not find any issue with how promises are designed. I think most of your confusion stems from the fact that you don't actually have any asynchronous operation inside your promise executor and thus there's really no reason to even use a promise for that. Promises are designed to track the pletion of asynchronous operations. No reason to use them if you don't have an actual asynchronous operation.
FYI, if you want to start some asynchronous operation at some time in the future from inside the promise executor, you can use the normal setTimeout()
or process.nextTick()
or setImmediate()
operations to schedule the operation to start later.
would have expected output to have been
Plus, it appears you are expecting your output to be in a strict order. Promise.all()
expects there to be N asynchronous operations running in parallel and there is no guaranteed order of pletion for those N operations. Instead, Promise.all()
will track them all, collect all the results and present the .then()
handler with an array of results in order (if they all resolved successfully). It does not run the operations themselves in order. The operations run in parallel and plete in whatever natural order they take.
Yes, promises execute right away. They couldn't work any other way. Promises, just like any other object in JS, are pletely unaware of what is referencing them and how they get passed around, so there's no way for them to "wait" until something particular is getting done with the references to them.
The solution in your case is to create the promises as you pass them to Promise.all()
:
let promiseFnArray = [];
const values = [1, 2, 3, 4, 5];
values.forEach((value) => {
promiseFnArray.push((resolve, reject) => {
console.log('value: ' + value);
return resolve();
}))
})
console.log('start')
Promise.all(promiseFnArray.map(promiseFn => new Promise(promiseFn));
Also, once your promises actually make something asynchronous, they won't necessarily resolve in the original order. To get the results in the correct order you use Promise.all( ... ).then()
, which is the entire purpose of Promise.all()