In a Node app, I need to iterate through some items in a synchronous fashion, but some of the operations inside the loop are asynchronous. My code right now looks like so:
someAPIpromise().then((items) => {
items.forEach((item) => {
Promise.all[myPromiseA(item), myPromiseB(item)]).then(() => {
doSomethingSynchronouslyThatTakesAWhile();
});
}
}
This works wonders when the items
is an array of 1. But, once there's more than one item, promise.all()
will just fire off instantly for every item in the array, without waiting for the operation in the loop to end.
All that to say... how can I ensure that the entire operation for each item in the array is run synchronously (even if some operations are async and return a promise)?
Thanks so much!
N
JavaScript Promises forEach with promises It is possible to effectively apply a function ( cb ) which returns a promise to each element of an array, with each element waiting to be processed until the previous element is processed.
all() The Promise. all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will fulfill when all of the input's promises have fulfilled, or if the input iterable contains no promises.
To use Javascript promises in a for loop, use async / await . This waits for each promiseAction to complete before continuing to the next iteration in the loop. In this guide, you learn how async/await works and how it solves the problem of using promises in for loops.
You're constructing several promises, but they are all asynchronous. You construct Promise1, Promise2, Promise3, ... but once they're in the wild they are all firing simultaneously. If you want synchronous behavior you've got to chain them together so Promise1's .then() executes Promise2 and so on. In the past I've used Array.reduce for this.
someAPIpromise().then((items) => {
items.reduce((accumulator, current) =>
accumulator.then(() =>
Promise.all[myPromiseA(item), myPromiseB(item)]).then(() =>
doSomethingSynchronouslyThatTakesAWhile();
)
)
, Promise.resolve());
You can write this as a helper function if you like, which may make things clearer.
function execSequentially (arr, func) {
return arr.reduce(
(accumulator, current) => accumulator.then(() => func(current)),
Promise.resolve());
}
That function is executed as
execSequentially(items, item => console.log(item));
of course replacing console.log with what you want to do.
The helper function approach is also less invasive of a change. The helper applied to your original code:
someAPIpromise().then((items) => {
execSequentially(items, (item) =>
Promise.all[myPromiseA(item), myPromiseB(item)]).then(() => {
doSomethingSynchronouslyThatTakesAWhile();
});
);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With