Reputation: 23
In javascript, I have an non flat array of Promises:
const array = [
[ promise11, promise12.. promise1n ],
[ promise21, promise22.. promise2n ],
[ promise31, promise32.. promise3n ],
...
[ promisek1, promisek2.. promisekn ]
];
How do iterate through the array in such a fashion, where the next array of promises would start resolving ONLY after the previous array of promises have resolved? For instance I would like the script to wait until [ promise11, promise12.. promise1n ]
promises resolve in parrallel, before calling on to the next array of promises.
I am looking for a general solution as my application cannot know in advance how many calls it'll have to make (it's a webscraper).
Upvotes: 1
Views: 2569
Reputation: 1073968
You could use a variation on the Array#reduce
pattern:
array.reduce(
(p, subArray) => p.then(() => Promise.all(subArray)),
Promise.resolve()
);
That sets up a promise chain where each entry in the chain is the result of the promise from Promise.all
for the subarrays in the array.
...but:
...where the next array of promises would start resolving ONLY after the previous array of promises have resolved?
That's not how promises work. Once you have the promise, the action it promises a result for is already in progress. You don't "start" it.
So instead, you'd want to make array
an array of functions that start the processes in question and return promises, which is slightly different:
function get(label) {
console.log(label + "- starting");
return new Promise(resolve => {
setTimeout(() => {
console.log(label + "- resolving");
resolve(label);
}, Math.random() * 500);
});
}
const array = [
[ get.bind(null, "1a"), get.bind(null, "1b"), get.bind(null, "1c") ],
[ get.bind(null, "2a"), get.bind(null, "2b") ],
[ get.bind(null, "3a"), get.bind(null, "3b"), get.bind(null, "3c"), get.bind(null, "3d") ]
];
array.reduce(
(p, subArray) => p.then(() => Promise.all(subArray.map(f => f()))),
Promise.resolve()
).then(() => {
console.log("All done");
});
.as-console-wrapper {
max-height: 100% !important;
}
Notice how the array is now an array of functions, which when called "start" the process and then return a promise. Our Array#reduce
loop is only slightly modified: We use Array#map
to call the functions for this subarray and get an array of their promises, which is what we feed into Promise.all
. So all of the functions for a given subarray are called to start the work for that subarray, and then we wait unti they're all complete before continuing to the next subarray and having it start its work.
Upvotes: 4