None of the answers provided thus far actually execute in the one at a time way you're looking for.
Promises invoke their executor function upon construction. So, by nature, in order to use Promise.all
, all of your async operations must already be running. Think of it as Promise.allAtOnce
.
@Daniel's answer comes close, but Array#forEach
executes synchronously, so it still runs all at once:
const wait = (time, message) => new Promise(resolve => {
setTimeout(_=>{
console.log(message);
resolve();
}, time);
});
let promises = [];
[3000, 2000, 1000].forEach(
(time, index) => promises.push(wait(time, ++index))
)
Promise.all(promises);
/*
Even though `3000` was the first item,
`1000` resolves first because all the `Promise`
executors run at once.
Output:
3
2
1
*/
The most succinct way to execute one at a time is with an async
loop:
const wait = (time, message) => new Promise(resolve => {
setTimeout(_=>{
console.log(message);
resolve();
}, time);
});
const iterate = async _ => {
let index = 0;
for (let time of [3000, 2000, 1000]) try {
await wait(time, ++index)
} catch (e) {
console.error(e);
}
}
iterate();
/*
Even though `3000` takes 3X longer to resolve,
the `wait` of `3000` resolves first,
because it is first in the iteration.
Output:
1
2
3
*/
If you want to avoid using async/await
, just chain the promises with a loop. This will produce the same result:
const wait = (time, message) => new Promise(resolve => {
setTimeout(_=>{
console.log(message);
resolve();
}, time);
});
const iterate = _ => {
// initiate with an already-resolved promise
let lastPromise = Promise.resolve();
let index = 0;
for (let time of [3000, 2000, 1000]) {
// chain each promise to the promise returned by the previous item.
lastPromise = lastPromise
.then(result => wait(time, ++index))
.catch(console.error);
}
return lastPromise;
}
iterate();
/*
Even though `3000` takes 3X longer to resolve,
the `wait` of `3000` resolves first,
because it is first in the iteration.
Output:
1
2
3
*/