Reputation: 5409
I am reducing an array of nested promises in the following way:
const promises = items.map((item, index) => {
console.log(index);
return doAsyncThing(item).then(() => {
console.log(index);
});
});
return promises.reduce((acc, p) => acc.then(() => p), Promise.resolve());
I want the console.log
entries to print out
0 0 1 1 2 2
but instead they are printing out
0 1 2 2 1 0
How can I restructure my code so that the entirety of operation 0 is completed before operation 1, which is completed before option 2, etc...?
Upvotes: 0
Views: 327
Reputation: 2032
The problem with your implementation is that all of the promises are created at the same time, and that will cause them to place their asynchronous actions in the event queue at that time. In your case, this is happening in the map
function. Let's walk through this.
// your current code
const promises = items.map((item, index) => {
console.log(index); // this happens immediately and waits for nothing, which is why you see `0 1 2` in the console
return doAsyncThing(item) // right here the async action is created
.then(() => { // this will run as soon as the async action is finished
console.log(index);
});
});
After this step, promises
is already an array of promises, all of which have already queued up their asynchronous actions, not waiting for any others to be completed.
You have the right idea with the reduce, but by the time your reduce runs, all of the promises are already created, and will run in whatever order they finish. If you want to enforce order, you will need to use the reduce to create the promises initially:
const promises = items.reduce((acc, item, index) => {
console.log(index) // still runs immediately
return acc
.then(() => doAsyncThing(item)) // creates the promise after acc finishes
.then(() => console.log(index)); // runs after doAsyncThing finishes
}, Promise.resolve());
This will produce the output 0 1 2 0 1 2
in your console, but action 1 will still not be run until action 0 finishes, and action 2 will not be run until action 1 finishes. I hope this helps!
Upvotes: 3