Promise Utilities

Learn the four static Promise combinator methods — Promise.all, Promise.allSettled, Promise.race, and Promise.any — and understand exactly when to use each one.

Real applications frequently need to run several promises at once and then do something once they're all done, once any one of them is done, or once the first successful one finishes. JavaScript provides four built-in static methods on the Promise object for exactly these situations, and each one behaves differently when some of the promises fail.

Promise.all — wait for every promise, fail if any one fails

Promise.all(promises) takes an array (or other iterable) of promises and returns a single promise that fulfills with an array of all the results, in the same order as the input, once every promise in the array has fulfilled.

If any single promise in the array rejects, Promise.all immediately rejects with that same error — it does not wait for the other promises to finish. This 'fail fast' behavior makes Promise.all ideal when you need all the results and having even one fail means the whole operation should be considered failed.

Promise.allSettled — wait for every promise, never fail

Promise.allSettled(promises) also waits for every promise to settle, but it never rejects — instead, it always fulfills with an array of result objects, one per input promise, each shaped as either { status: "fulfilled", value } or { status: "rejected", reason }.

This is the right choice when you want to know the outcome of every operation regardless of whether some failed — for example, sending several independent notifications and wanting a full report of which succeeded and which didn't, without one failure hiding the results of the others.

Promise.race — settle as soon as the first promise settles

Promise.race(promises) returns a promise that settles (fulfills or rejects) as soon as the very first promise in the array settles, taking on that same outcome — whether it was a success or a failure. The other promises keep running in the background, but their eventual results are ignored by the race.

A very common real use of Promise.race is implementing a timeout: race the real operation against a promise that rejects after a fixed delay, so that if the real operation takes too long, the timeout rejection wins the race.

Promise.any — settle as soon as the first promise succeeds

Promise.any(promises) returns a promise that fulfills as soon as the first input promise fulfills, ignoring rejections along the way — unlike Promise.race, a rejection from one promise doesn't end the race, because Promise.any is specifically looking for the first success.

Only if every single promise in the array rejects does Promise.any itself reject, with a special AggregateError that bundles together all of the individual rejection reasons in its errors property.

The four Promise combinators

All four methods accept an array (or other iterable) of promises and each returns a single new promise. Promise.all and Promise.race are 'fail fast' in the sense that a rejection can settle the returned promise immediately; Promise.allSettled never rejects, and Promise.any only rejects if everything fails.

const results = await Promise.all([p1, p2, p3]);
// fulfills with [v1, v2, v3], or rejects on the first rejection

const outcomes = await Promise.allSettled([p1, p2, p3]);
// always fulfills: [{status, value|reason}, ...]

const first = await Promise.race([p1, p2, p3]);
// settles with whichever promise settles first (success or failure)

const firstSuccess = await Promise.any([p1, p2, p3]);
// fulfills with the first success; rejects with AggregateError only if all reject

Code Examples

All three fetchPrice calls start immediately and run concurrently. Promise.all waits for the slowest one (cherry, 300ms) and then resolves with an array containing all three results, in the original order — not the order they finished in. Expected result: [ { item: 'apple', price: ... }, { item: 'banana', price: ... }, { item: 'cherry', price: ... } ] (after ~300ms)

The results array preserves input order (apple, banana, cherry) even though banana actually finishes first.

Even though the Database check rejects, Promise.allSettled still waits for and reports on Auth and Cache — nothing is lost, and the whole allSettled promise itself always fulfills, with a status field marking which individual checks failed. Expected result: OK: Auth is up FAILED: Database is down OK: Cache is up r.status === "fulfilled" vs r.status === "rejected" is how you distinguish individual outcomes inside the results array.

slowOperation takes 2000ms, but the timeout promise rejects after only 500ms. Promise.race settles with whichever promise finishes first — here, the timeout wins, so the race rejects with "Timed out" long before slowOperation would have resolved. Expected result: Failed: Timed out

Promise.race([promise, timeout]) settles with the outcome of whichever of the two finishes first, success or failure.

mirror1 rejects fastest (300ms) but Promise.any ignores that rejection and keeps waiting. mirror2 succeeds at 500ms, which becomes the first success, so Promise.any fulfills with mirror2's result — mirror3 is still ignored even though it would also have succeeded. Expected result: First success: mirror2 responded

A rejection from mirror1 does not end the Promise.any race — only the first fulfillment does.

function fetchPrice(item, ms) {
  return new Promise(resolve => setTimeout(() => resolve({ item, price: Math.random() * 100 }), ms));
}

async function getAllPrices() {
  const results = await Promise.all([
    fetchPrice("apple", 200),
    fetchPrice("banana", 100),
    fetchPrice("cherry", 300)
  ]);
  console.log(results);
}

getAllPrices();
function checkService(name, shouldFail) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      shouldFail ? reject(new Error(name + " is down")) : resolve(name + " is up");
    }, 100);
  });
}

async function checkAll() {
  const results = await Promise.allSettled([
    checkService("Auth", false),
    checkService("Database", true),
    checkService("Cache", false)
  ]);
  results.forEach(r => {
    if (r.status === "fulfilled") {
      console.log("OK:", r.value);
    } else {
      console.log("FAILED:", r.reason.message);
    }
  });
}

checkAll();
function fetchWithTimeout(promise, ms) {
  const timeout = new Promise((_, reject) => {
    setTimeout(() => reject(new Error("Timed out")), ms);
  });
  return Promise.race([promise, timeout]);
}

function slowOperation() {
  return new Promise(resolve => setTimeout(() => resolve("data"), 2000));
}

fetchWithTimeout(slowOperation(), 500)
  .then(result => console.log("Got:", result))
  .catch(error => console.log("Failed:", error.message));
function fetchFromMirror(name, ms, shouldFail) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      shouldFail ? reject(new Error(name + " failed")) : resolve(name + " responded");
    }, ms);
  });
}

Promise.any([
  fetchFromMirror("mirror1", 300, true),
  fetchFromMirror("mirror2", 500, false),
  fetchFromMirror("mirror3", 700, false)
])
  .then(result => console.log("First success:", result))
  .catch(error => console.log("All failed:", error.errors));

The four Promise combinators compared

Choose Promise.all when every result is required, allSettled when you want a full report regardless of failures, race for 'whichever finishes first, win or lose' (e.g. timeouts), and any for 'the first one that actually succeeds.'

Promise.all([p1,p2,p3])
  waits for ALL to fulfill → [v1,v2,v3]
  ANY rejection → rejects immediately

Promise.allSettled([p1,p2,p3])
  waits for ALL to settle → [{status,value|reason}, ...]
  NEVER rejects

Promise.race([p1,p2,p3])
  settles on the FIRST to settle (success OR failure)

Promise.any([p1,p2,p3])
  settles on the FIRST to FULFILL
  rejects only if ALL reject (AggregateError)

Important Rules

Promise.all fulfills with all results in input order, but rejects immediately on the first rejection.

Promise.allSettled always fulfills, giving a { status, value | reason } object per input promise — it never rejects.

Promise.race settles with whichever promise settles first, whether that promise fulfilled or rejected.

Promise.any fulfills with the first fulfillment and ignores rejections, only rejecting (with an AggregateError) if every promise rejects.

All four methods run the input promises concurrently — they don't start them sequentially.

Where this shows up

Promise.all is common for loading several independent pieces of page data before rendering (e.g. user profile plus their posts plus their settings). Promise.allSettled fits health checks or batch operations where partial failure is expected and must be reported. Promise.race is the standard way to implement request timeouts. Promise.any is used for redundancy, such as querying multiple mirrored servers and using whichever responds successfully first.

"I'll use Promise.all to check the status of several independent services, since I want to know about every one even if some fail."

Use Promise.allSettled for that case — Promise.all would reject and discard the successful results the moment any single service check fails.

Promise.all's fail-fast behavior means one failure hides every other result; allSettled is specifically designed to report on all outcomes, successes and failures alike.

"Promise.race and Promise.any do the same thing." Promise.race settles on whichever promise finishes first, success or failure; Promise.any specifically waits for the first success and ignores failures unless everything fails.

Confusing race and any leads to bugs: race can resolve your logic with an error if the fastest promise happens to reject, while any would correctly keep waiting for a later success in that same scenario.

[Multiple Choice] You need to load a user's profile, posts, and settings in parallel, and if ANY of the three requests fails, you want the whole operation to fail immediately. Which Promise utility fits best? A. Promise.allSettled B. Promise.race C. Promise.all D. Promise.any

C. Promise.all — Promise.all is the right choice when every result is required and a single failure should immediately fail the whole operation — exactly this scenario.

Given three promises that fetch data from three different CDNs (some of which may fail), write code using the correct Promise utility to get the very first successful response, and log a friendly error only if all three CDNs fail.

Promise.any([fetchFromCdn1(), fetchFromCdn2(), fetchFromCdn3()]) .then(data => console.log("Loaded from fastest working CDN:", data)) .catch(err => console.log("All CDNs failed:", err.errors));

You want the first success while ignoring individual failures — that is exactly what Promise.any is for.