DEV Community

Cover image for The Hidden Danger of Promise.all() in JavaScript
Amin Sadeghi
Amin Sadeghi

Posted on

The Hidden Danger of Promise.all() in JavaScript

Promise.all() is one of the most useful tools in JavaScript for handling multiple asynchronous operations.

It allows us to run several promises concurrently and wait until all of them are fulfilled.

But there's something developers often overlook:

When one promise rejects, Promise.all() rejects immediately, but the other operations don't automatically stop.

Let's understand why this matters.

1. The Problem

Imagine fetching user information, notifications, and account settings simultaneously:

const [user, notifications, settings] = await Promise.all([
  fetchUser(),
  fetchNotifications(),
  fetchSettings()
]);
Enter fullscreen mode Exit fullscreen mode

This looks perfectly fine.

But what happens if fetchNotifications() fails?

Promise.all() rejects, and execution moves to the catch block.

However, fetchUser() and fetchSettings() may still be running.

JavaScript doesn't automatically cancel the remaining promises.

This can become problematic when those operations involve expensive requests or side effects.

2. Promise.all() Doesn't Cancel Anything

Consider this example:

const delay = (ms) =>
  new Promise((resolve) => setTimeout(resolve, ms));

const task1 = delay(1000).then(() => {
  console.log("Task 1 completed");
});

const task2 = delay(2000).then(() => {
  throw new Error("Task 2 failed");
});

const task3 = delay(3000).then(() => {
  console.log("Task 3 completed");
});

try {
  await Promise.all([task1, task2, task3]);
} catch (error) {
  console.log(error.message);
}
Enter fullscreen mode Exit fullscreen mode

The output will be:

Task 1 completed
Task 2 failed
Task 3 completed
Enter fullscreen mode Exit fullscreen mode

Notice that Task 3 still completes after Promise.all() has already rejected.

That's because Promise rejection and operation cancellation are two different things.

3. What If You Want Every Result?

Sometimes, failing the entire operation because one promise rejects isn't what you want.

For example, when loading several independent dashboard sections, you may want successful results even if one request fails.

That's where Promise.allSettled() becomes useful:

const results = await Promise.allSettled([
  fetchUser(),
  fetchNotifications(),
  fetchSettings()
]);

for (const result of results) {
  if (result.status === "fulfilled") {
    console.log("Success:", result.value);
  } else {
    console.error("Failed:", result.reason);
  }
}
Enter fullscreen mode Exit fullscreen mode

Unlike Promise.all(), it waits for every promise to settle, regardless of whether it fulfilled or rejected.

4. What If You Actually Need Cancellation?

For operations that support cancellation, such as fetch(), you can use AbortController.

const controller = new AbortController();

try {
  const results = await Promise.all([
    fetch("/api/users", {
      signal: controller.signal
    }),
    fetch("/api/notifications", {
      signal: controller.signal
    }),
    fetch("/api/settings", {
      signal: controller.signal
    })
  ]);

} catch (error) {
  controller.abort();
  throw error;
}
Enter fullscreen mode Exit fullscreen mode

If one request rejects, the controller aborts the other requests that are still in progress.

Keep in mind that cancellation is cooperative. It doesn't guarantee that server-side processing has stopped.

5. Which One Should You Use?

Method Behavior
Promise.all() Rejects when the first promise rejects
Promise.allSettled() Waits for every promise to settle
Promise.race() Settles with the first settled promise
Promise.any() Fulfills with the first fulfilled promise

Each method solves a different problem.

Choosing the right one depends on what your application expects when asynchronous operations fail.

Final Thoughts

Asynchronous JavaScript isn't just about running multiple operations at the same time.

It's also about understanding failure behavior, cancellation, and how independent operations affect each other.

A small misunderstanding about promises can create unexpected behavior in production.

Here's a question:

When building a dashboard with multiple independent API requests, would you use Promise.all() or Promise.allSettled()?

And more importantly, why?

Let's discuss.

Top comments (0)