Promise.allSettled: keep the results that succeeded
Promise.all throws away every result when one request fails. Promise.allSettled waits for all of them and reports each outcome, so one failure cannot empty a page.
A dashboard loads a profile, a list of orders and a set of offers. The offers service has a bad moment. With Promise.all, the whole page fails, although two of the three requests worked.
// One rejection rejects everything. The other results are lost.
const [profile, orders, offers] = await Promise.all([getProfile(), getOrders(), getOffers()]);
Promise.allSettled is built for this case.
How it works
It waits until every promise has finished, whether it succeeded or failed, and it never rejects. You get one result object per promise, in the same order.
const results = await Promise.allSettled([getProfile(), getOrders(), getOffers()]);
// [
// { status: "fulfilled", value: { name: "Rafi" } },
// { status: "fulfilled", value: [/* orders */] },
// { status: "rejected", reason: Error("503 Service Unavailable") }
// ]
A fulfilled result has a value. A rejected one has a reason.
Use the successes, report the failures
const [profile, orders, offers] = results.map((result) =>
result.status === "fulfilled" ? result.value : null,
);
results
.filter((result) => result.status === "rejected")
.forEach((result) => logger.warn({ err: result.reason }, "Dashboard section failed"));
render({ profile, orders, offers }); // offers is null, so that section shows a retry link
The page shows the profile and the orders, and the offers section explains that it could not load. One failure stays one failure.
Choosing the right combinator
| Method | Resolves when | Rejects when | Use it for |
|---|---|---|---|
Promise.all |
All succeed | Any one fails | Steps that are all required |
Promise.allSettled |
All have finished | Never | Independent tasks where partial results are useful |
Promise.any |
The first one succeeds | All fail | Trying several sources for the same thing |
Promise.race |
The first one finishes | The first one fails | Timeouts and "whichever answers first" |
Promise.all is still the right choice when the results depend on each other. If you cannot create an order without both the stock check and the payment, failing fast is what you want.
Two things to remember
You must check the statuses. Because allSettled never rejects, a try/catch around it catches nothing. If you ignore the rejected entries, the errors disappear silently.
It waits for everything. One hanging request delays the whole result. Give each request a timeout:
const getOffers = () => fetch("/api/offers", { signal: AbortSignal.timeout(3000) });
Where it fits
- loading independent sections of a page,
- sending notifications to many recipients,
- running a batch of uploads and reporting which ones failed,
- cleanup steps that should all be attempted.
For the wider pattern of catching and reporting failures, see async error handling in JavaScript.