The Javascript function Promise.allSettled waits for all resolved or rejected promises to finish. Promise.all won't return the resolved promises if any of them are rejected, and Promise.race and Promise.any only give the first settled or fufilled promise.
Is there a way to send off multiple promises (say 100), and then as soon as one fails (perhaps have 20 succeed) cancel the unsettled promises (of which there are 100 - 20 - 1 = 79 not yet settled)? I don't even need the details of which failed, but just a sort of Promise.someSettled function.
For context, I'm mapping between data and fetch calls, and I'd like to know what fetches need to be retried.
Is that possible?
Because the input promises and output resolve values aren't one-to-one, I think the easiest way to manage this would be to just push to an outer array on resolve, and use Promise.all to wait for one rejection, something like:
const makePromises = () => Array.from(
{ length: 100 },
(_, i) => new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.05) resolve(i);
else reject();
}, 1000 * Math.random());
})
);
const resolveValues = [];
Promise.all(
makePromises()
.map(prom => prom.then(val => {
resolveValues.push(val);
}))
)
.then(() => {
console.log('Unexpected - All promises resolved');
})
.catch(() => {
const innerResolveValues = [...resolveValues];
console.log('Done:');
console.log(innerResolveValues);
});
It sounds like you're trying to build a progress indicator for a large number of calls.
A simple solution would be to break the large number of calls into smaller groups and use Promise.allSettled() to determine when each group is finished. You can then compare the number of finished groups to the number of unfinished groups to get a measurement of progress.
Yes, @Certainperformance hit it on the head! Here is another way of assembling the array of promises but the idea is exactly the same:
for (var acc=[], pr=[], i=0; i<100; i++)
pr.push(new Promise((rs,rj)=>setTimeout((i<20?rs:rj).bind(null,i),200*i))
.then(d=>{acc.push(d)}))
Promise.all(pr).then(
d=>{console.log("all done!", acc)},
e=>{console.log("with some errors:", acc)} );
.as-console-wrapper {max-height: 100% !important; top: 0; }
In my example I let the first finishing promises succeed and reject the later ones (for i>=20). The promises finish in a sequence of 0.2s one after another. So, after 4.2 seconds the first rejected promise is returned and the "failure" branch of the outer .then() will be executed, listing the accumulated successful promises in acc.