# JavaScript Promise Patterns: all, race, any, and allSettled

Source: https://devdocs10.com/articles/javascript/js-promise-patterns  
By Murat Bo · Published 2026-07-13 · DevDocs10 (https://devdocs10.com)

Promise combinators let you coordinate multiple asynchronous operations in JavaScript with a single line of code. This article explains how `Promise.all`, `Promise.race`, `Promise.any`, and `Promise.allSettled` behave, when to use each one, and how to avoid the mistakes that often trip up developers.

> **Quick answer:** Use `Promise.all` when every task must succeed, `Promise.race` when you want the first settled result, `Promise.any` when you want the first successful result, and `Promise.allSettled` when you need every outcome no matter what.

> **Difficulty:** Intermediate
>
> **You'll understand this better if you know:** how promises represent async results, how `async`/`await` works, and the difference between fulfillment and rejection.

## 1. What Are Promise Patterns?

Promise patterns are built-in methods that combine multiple promises into one result. They solve a common problem: when your code starts several asynchronous tasks at once, you need a predictable way to wait for them, react to the first one that finishes, or inspect every outcome.

- `Promise.all` waits for all promises to fulfill.
- `Promise.race` settles as soon as the first promise settles, whether that is fulfillment or rejection.
- `Promise.any` fulfills as soon as one promise fulfills.
- `Promise.allSettled` waits for every promise to finish and reports each result.

These methods are often called promise combinators because they combine multiple async operations into one promise.

## 2. Why Promise Patterns Matter

Real applications often need to fetch multiple resources, run several checks in parallel, or provide a fallback when one service is slow. Promise patterns help you write that logic clearly instead of manually counting completions and tracking state.

They also make your code easier to reason about. Instead of nesting callbacks or writing custom bookkeeping, you can express your intent directly: wait for everything, use the fastest response, accept the first success, or collect all results.

## 3. Basic Syntax

All four methods accept an iterable, usually an array of promises. The return value is always a promise, but each method resolves according to a different rule.

### Promise.all syntax

Use `Promise.all` when all results matter and a single failure should fail the whole operation.

```javascript
const results = await Promise.all([promiseA, promiseB, promiseC]);
```

If every promise fulfills, the returned array preserves the original order of the input, not the completion order.

### Promise.race syntax

Use `Promise.race` when the first settled outcome should win.

```javascript
const winner = await Promise.race([promiseA, promiseB]);
```

The returned promise settles with the same value or reason as the first promise to settle.

### Promise.any syntax

Use `Promise.any` when you want the first successful result and can ignore earlier failures.

```javascript
const value = await Promise.any([promiseA, promiseB]);
```

If every promise rejects, the returned promise rejects with an `AggregateError`.

### Promise.allSettled syntax

Use `Promise.allSettled` when you need the result of every promise, even if some fail.

```javascript
const outcomes = await Promise.allSettled([promiseA, promiseB]);
```

The result is an array of objects describing whether each promise was fulfilled or rejected.

## 4. Step-by-Step Examples

### Example 1: Waiting for every request with Promise.all

Suppose you need a profile, notifications, and settings before rendering a dashboard. You can start the requests together and wait until all of them finish.

```javascript
const profilePromise = fetch("/api/profile").then(response => response.json());
const notificationsPromise = fetch("/api/notifications").then(response => response.json());
const settingsPromise = fetch("/api/settings").then(response => response.json());

const [profile, notifications, settings] = await Promise.all([
  profilePromise,
  notificationsPromise,
  settingsPromise
]);
```

This pattern is useful when every value is required. If one request fails, the whole operation rejects immediately.

### Example 2: Using the fastest response with Promise.race

Imagine a request that may be served from a cache or from the network. You can race them and take the first one to settle.

```javascript
const cachePromise = readFromCache("user:42");
const networkPromise = fetch("/api/users/42").then(response => response.json());

const result = await Promise.race([
  cachePromise,
  networkPromise
]);
```

The first settled promise wins, even if that outcome is a rejection. That makes `Promise.race` useful for timeouts and fallback strategies, but it also means you must be careful about failures.

### Example 3: Accepting the first success with Promise.any

If you have multiple mirrors for the same resource, you may want the first successful response and ignore early failures.

```javascript
const mirrorA = fetch("https://mirror-a.example.com/data.json").then(response => response.json());
const mirrorB = fetch("https://mirror-b.example.com/data.json").then(response => response.json());
const mirrorC = fetch("https://mirror-c.example.com/data.json").then(response => response.json());

const data = await Promise.any([mirrorA, mirrorB, mirrorC]);
```

This is different from `Promise.race`. A rejected promise does not win unless every promise rejects.

### Example 4: Collecting all outcomes with Promise.allSettled

When you need to report which tasks succeeded and which failed, `Promise.allSettled` is the safest choice.

```javascript
const tasks = [
  fetch("/api/a"),
  fetch("/api/b"),
  fetch("/api/c")
];

const results = await Promise.allSettled(tasks);

for (const result of results) {
  if (result.status === "fulfilled") {
    console.log(result.value);
  } else {
    console.error(result.reason);
  }
}
```

The result array gives you one object per input promise, making it easy to display partial success.

## 5. Practical Use Cases

- Load several API resources in parallel before rendering a view.
- Use a timeout by racing a request against a timer promise.
- Query redundant services and accept the first successful response.
- Run batch jobs where every result must be reported, even failures.
- Process multiple uploads and show a per-file success or failure summary.

These patterns appear in dashboards, search, file processing, monitoring tools, and reliability-sensitive applications.

## 6. Common Mistakes

### Mistake 1: Expecting Promise.all to keep successful results after one failure

`Promise.all` rejects as soon as any input promise rejects. Many beginners expect it to return the successful values and ignore the failure, but that is what `Promise.allSettled` is for.

**Problem:** If one request fails, the whole `Promise.all` call rejects and you do not get a partial array of fulfilled values.

```javascript
const profile = fetch("/api/profile").then(response => response.json());
const settings = fetch("/api/settings").then(response => response.json());
const badRequest = Promise.reject(new Error("settings unavailable"));

const data = await Promise.all([profile, settings, badRequest]);
```

**Fix:** Use `Promise.allSettled` when you want every outcome, or catch errors before combining them if a fallback is acceptable.

```javascript
const results = await Promise.allSettled([profile, settings, badRequest]);

const successfulValues = results
  .filter(result => result.status === "fulfilled")
  .map(result => result.value);
```

The corrected version works because it is designed for mixed success and failure.

### Mistake 2: Using Promise.race when you really want the first success

`Promise.race` does not ignore rejections. If the fastest promise rejects, the entire race rejects immediately.

**Problem:** A slow successful request cannot save the result if a faster request fails first.

```javascript
const fastFail = Promise.reject(new Error("cache miss"));
const slowSuccess = new Promise(resolve => setTimeout(() => resolve("network data"), 100));

const value = await Promise.race([fastFail, slowSuccess]);
```

**Fix:** Use `Promise.any` when you need the first fulfilled result, not the first settled result.

```javascript
const value = await Promise.any([fastFail, slowSuccess]);
```

The corrected version waits for the first success instead of failing on the first rejection.

### Mistake 3: Ignoring Promise.any rejection behavior

Some developers assume `Promise.any` never rejects because it can skip failures. In reality, it rejects when all input promises reject, and the error is an `AggregateError`.

**Problem:** If every promise fails, the catch block receives an aggregate of all reasons, not a normal single error message.

```javascript
try {
  await Promise.any([
    Promise.reject(new Error("A failed")),
    Promise.reject(new Error("B failed"))
  ]);
} catch (error) {
  console.log(error.message);
}
```

Output (tested with Node 24.21.0):

```text
All promises were rejected
```

**Fix:** Check for `AggregateError` and inspect its `errors` array when you need the reasons for failure.

```javascript
try {
  await Promise.any([
    Promise.reject(new Error("A failed")),
    Promise.reject(new Error("B failed"))
  ]);
} catch (error) {
  if (error instanceof AggregateError) {
    for (const reason of error.errors) {
      console.error(reason.message);
    }
  }
}
```

Output (tested with Node 24.21.0):

```text
A failed
B failed
```

The corrected version handles the real shape of the failure.

## 7. Best Practices

### Practice 1: Start independent promises before awaiting

To get real concurrency, create the promises first and await the combined result afterward. If you await each request one by one, you turn parallel work into serial work.

```javascript
const userPromise = fetch("/api/user");
const postsPromise = fetch("/api/posts");

const [userResponse, postsResponse] = await Promise.all([userPromise, postsPromise]);
```

This pattern reduces total wait time because both requests run at the same time.

### Practice 2: Choose the combinator that matches your failure policy

Your error strategy should drive the method you choose. If the task fails when any part fails, use `Promise.all`. If partial results are acceptable, use `Promise.allSettled`. If one success is enough, use `Promise.any`.

```javascript
const chosen = await Promise.allSettled([taskA, taskB, taskC]);
```

Matching the method to the business rule makes code easier to maintain and less surprising.

### Practice 3: Handle rejected outcomes explicitly

With `Promise.allSettled`, do not assume every result has a value. Read the `status` field before touching `value` or `reason`.

```javascript
const results = await Promise.allSettled([taskA, taskB]);

for (const result of results) {
  if (result.status === "fulfilled") {
    console.log(result.value);
  }
}
```

Output (tested with Node 24.21.0):

```text
Uncaught ReferenceError: taskA is not defined
```

This avoids undefined access and keeps your success and failure paths clear.

## 8. Limitations and Edge Cases

- `Promise.race` does not mean “fastest success”; it means “first settled promise,” which can be a rejection.
- `Promise.any` requires at least one fulfillment and throws `AggregateError` if all promises reject.
- `Promise.all` keeps the order of inputs, not the order in which promises finish.
- Passing plain values instead of promises usually works because these methods wrap them with `Promise.resolve`, but that can hide mistakes in async logic.
- None of these methods cancel the promises that lose the race or are no longer needed; the underlying work may continue unless you add cancellation yourself.

That last point matters in browser and server code alike. If you are racing fetch requests, the slower ones may still consume bandwidth unless you explicitly abort them with a separate cancellation mechanism.

## 9. Practical Mini Project

Here is a small dashboard helper that loads three widgets in parallel, accepts the first successful fallback source for featured content, and records which widgets failed without breaking the page.

```javascript
async function loadDashboard() {
  const statsPromise = fetch("/api/stats").then(response => response.json());
  const alertsPromise = fetch("/api/alerts").then(response => response.json());
  const featuredA = fetch("/api/featured-a").then(response => response.json());
  const featuredB = fetch("/api/featured-b").then(response => response.json());

  const [statsResult, alertsResult] = await Promise.allSettled([
    statsPromise,
    alertsPromise
  ]);

  let featured;
  try {
    featured = await Promise.any([featuredA, featuredB]);
  } catch {
    featured = null;
  }

  return {
    stats: statsResult.status === "fulfilled" ? statsResult.value : null,
    alerts: alertsResult.status === "fulfilled" ? alertsResult.value : null,
    featured
  };
}
```

This example shows a realistic combination of promise patterns: `allSettled` for partial data, `any` for fallback content, and normal promise chaining for JSON parsing.

## 10. Key Points

- `Promise.all` is for “all must succeed.”
- `Promise.race` is for “first settled wins.”
- `Promise.any` is for “first fulfilled wins.”
- `Promise.allSettled` is for “show me every outcome.”
- The returned results preserve input order, even when completion order differs.
- These methods do not cancel slower promises automatically.

## 11. Practice Exercise

- Create three promises that resolve after different delays.
- Use `Promise.all` to wait for them and print the results in input order.
- Then change one promise to reject and compare the behavior of `Promise.all` and `Promise.allSettled`.

**Expected output:** The `Promise.all` version should log an array only when all promises fulfill. The `Promise.allSettled` version should log one result object per promise, including the rejection.

**Hint:** Use `setTimeout` inside `new Promise` to control the timing.

```javascript
const makePromise = (label, delay, shouldReject = false) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (shouldReject) {
        reject(new Error(`${label} failed`));
      } else {
        resolve(label);
      }
    }, delay);
  });
};

const a = makePromise("A", 300);
const b = makePromise("B", 100, true);
const c = makePromise("C", 200);

try {
  const allResults = await Promise.all([a, b, c]);
  console.log(allResults);
} catch (error) {
  console.error(error.message);
}

const settledResults = await Promise.allSettled([a, b, c]);
console.log(settledResults);
```

Output (tested with Node 24.21.0):

```text
B failed
[ { status: "fulfilled", value: "A" }, { status: "rejected", reason: Error: B failed }, { status: "fulfilled", value: "C" } ]
```

## 12. Final Summary

Promise patterns give you a compact, reliable way to coordinate multiple asynchronous operations in JavaScript. The key is to match the method to the behavior you want: wait for everything with `Promise.all`, use the first settled value with `Promise.race`, accept the first success with `Promise.any`, or inspect every outcome with `Promise.allSettled`.

Once you understand the difference between settlement and fulfillment, these methods become easy to choose correctly. They are especially useful for API requests, fallback systems, batch processing, and partial-failure reporting.

Next, practice combining these methods with `async`/`await` and timed requests so you can recognize which pattern fits a given problem quickly.

## Browser Support

| Feature | Status | Chrome | Edge | Firefox | Safari | Safari iOS |
| --- | --- | --- | --- | --- | --- | --- |
| Promise.allSettled() | Widely available since Jan 2023 | 76+ | 79+ | 71+ | 13+ | 13+ |
| Promise.any() | Widely available since Mar 2023 | 85+ | 85+ | 79+ | 14+ | 14+ |
| AbortSignal.any() | Widely available since Sep 2026 | 116+ | 116+ | 124+ | 17.4+ | 17.4+ |

Data: web-features 3.43.0 (MDN Baseline).
