Avoid UI Crashes: Mastering Promise.all vs. Promise.allSettled in JavaScript
When fetching multiple APIs concurrently, Promise.all aborts all results if any request fails, leading to poor user experience, whereas Promise.allSettled returns outcomes for every promise without rejecting, allowing graceful handling of partial failures and more robust UI rendering.
When we need to manage multiple concurrent tasks such as simultaneous API requests, parallel file processing, or independent animations, we require a reliable mechanism.
For a long time Promise.all has been the default choice, but it has a fatal flaw.
Promise.all
Consider an example where we need to fetch data from three different APIs to render a dashboard page:
const api1 = fetch('/api/user-info');
const api2 = fetch('/api/dashboard-widgets');
const api3 = fetch('/api/notifications');
Promise.all([api1, api2, api3])
.then(([userInfo, widgets, notifications]) => {
// All three requests succeeded
console.log('All data loaded successfully!');
renderDashboard(userInfo, widgets, notifications);
})
.catch(error => {
// As soon as any request fails, this runs
console.error('Load failed:', error);
showErrorUI();
});Imagine api1 and api2 succeed, but api3 fails because the server hiccups. The whole operation crashes due to a non‑essential notification feature, which is a poor user experience.
This illustrates the core risk of Promise.all: it ignores the promises that have already fulfilled, and if any promise rejects, all results are lost.
Promise.allSettled
To solve this problem, ECMAScript introduced Promise.allSettled, which follows a completely different philosophy and acts as a more tolerant and robust concurrent processor. Promise.allSettled also receives an array of promises, but its behavior is:
Its returned promise never rejects, regardless of individual outcomes.
Its resolved value is an array of objects, each describing the final state of the corresponding promise.
Each result object has one of two shapes:
{ status: 'fulfilled', value: <parsed value> } { status: 'rejected', reason: <rejection reason> }Rewriting the previous example with Promise.allSettled:
const api1 = fetch('/api/user-info');
const api2 = fetch('/api/dashboard-widgets');
const api3 = fetch('/api/notifications'); // assume this fails
Promise.allSettled([api1, api2, api3])
.then(results => {
// We can safely handle each result; assume api3 failed
if (results[2].status === 'rejected') {
console.warn('Notification load failed:', results[2].reason);
// Even though notifications failed, other parts can still render
showNotificationFallback();
}
// Process successful results (api1 and api2)
// ...
});
// Note: .catch() is rarely needed here because the aggregate promise never rejects.By using Promise.allSettled, even if api3 fails we still obtain the successful results of api1 and api2 and can handle them individually, greatly improving the robustness of the application. Promise.allSettled provides a never‑failing promise aggregation method, enabling finer‑grained and safer handling of concurrent tasks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaScript
Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
