Promise.any()

ES2021+

Returns a promise that fulfills when any of the promises fulfills, or rejects if all of the promises reject.

Syntax

Promise.any(iterable)

Parameters

iterable Iterable

An iterable of promises

Return Value

Promise

A Promise that fulfills with the first fulfilled promise

Examples

JavaScript
Promise.any([
  Promise.reject('에러1'),
  Promise.resolve('성공!'),
  Promise.reject('에러2')
]).then(value => console.log(value));
Output:
// '성공!'

📌 When to Use

Use Promise.any() when several sources can each satisfy the request and you want the first success, treating individual failures as noise. It is the natural fit for redundancy: query three CDN mirrors and take whichever responds, resolve a name against multiple DNS-over-HTTPS providers, or read a value from memory cache, disk cache, and network simultaneously and use the fastest hit. Unlike Promise.race(), a rejection does not decide the outcome — any() keeps waiting while at least one input is still pending, and only rejects (with an AggregateError bundling every reason) once all inputs have failed. That makes its failure mode meaningful: 'nothing worked', rather than race()'s 'the first thing that happened was bad'. It also suits graceful degradation across API versions: try the new endpoint and the legacy endpoint together and take whichever fulfills. Two cautions shape real-world use. First, the losing requests keep running after a winner settles, so pair any() with AbortController when the redundant work is expensive. Second, it is an ES2021 feature, so verify runtime support or ship a polyfill for older targets. And if every failure matters individually — you need a per-source report, not just a winner — Promise.allSettled() is the better instrument.

⚠️ Common Mistakes

Catching the failure and treating it like a single error. When every input rejects, any() rejects with an AggregateError whose own message is generic; the useful information lives in error.errors, an array of the individual reasons in input order. Log that array, or you will be debugging blind.

Deploying to older environments without checking support: Promise.any() and AggregateError arrived in ES2021 (Node.js 15+). On older targets the call throws a TypeError at runtime — a failure mode your tests on modern machines will never reproduce.

Confusing its semantics with race(). any() ignores rejections until all inputs fail, while race() settles on the first settlement of either kind — a fast failure ends a race() immediately but leaves any() waiting for the slower candidates. Choosing the wrong combinator silently changes your error behavior.

Passing an empty array and expecting it to hang the way race([]) does: any([]) rejects immediately with an AggregateError. Dynamically built candidate lists need a guard if 'no candidates' should mean something other than instant failure.

Letting the losing requests run to completion. After the first success the redundant fetches keep downloading, multiplying bandwidth and backend load on every call. Abort the losers with AbortController once a winner settles — especially important on metered mobile connections.

✅ Best Practices

Use it to make redundancy cheap: fire the same request at independent replicas and take the fastest success. Availability improves multiplicatively — all sources must fail before you do — while latency drops to that of the fastest healthy source.

Always inspect AggregateError.errors on total failure — catch(e => console.log(e.errors)) — and include the per-source detail in whatever you log or rethrow; 'all endpoints failed' plus three distinct reasons is an actionable alert, the bare message alone is not.

Create one AbortController per candidate and cancel the rest in a finally() after the first fulfillment, so redundancy costs approximately one response instead of N full downloads.

Input order never changes who wins — the fastest success does — but keep the candidate array's order stable anyway: AggregateError.errors follows it, and stable ordering turns your failure logs into a readable per-source report.

⚡ Performance Notes

any() is the latency-optimization combinator: expected response time is the minimum of the candidates' success latencies, which for independent sources beats any single source on average and smooths over tail-latency spikes. The bookkeeping matches the other combinators — one reaction record per input, settlement delivered on the microtask queue, one wrapper promise — so its own cost is negligible. The real budget item is duplicated work: N parallel attempts consume N times the bandwidth, connections, and server CPU, and the losers do not stop when a winner settles unless you abort them. That trade is excellent for small, critical requests such as configuration blobs, auth tokens, or first-paint data, and wasteful for large payloads, where a quick health-check race followed by a single full download from the winner is far cheaper. Worst case — all inputs reject — costs the maximum of the failure latencies plus construction of an AggregateError referencing every reason.

🌍 Real World Example

Multi-CDN Resource Loader

A multi-CDN loader that requests the same asset from three mirrors and resolves with the first healthy response. Note how each fetch validates response.ok and throws on HTTP errors, so a fast 500 from a broken mirror counts as a loss rather than winning the race. Only when every mirror fails does the catch block run, logging each mirror's individual error from aggregateError.errors before surfacing one summary failure. The pattern turns a flaky CDN from a user-visible outage into an invisible latency blip, at the cost of duplicate requests.

async function loadFromCDN(resourcePath) {
  const cdns = [
    'https://cdn1.example.com',
    'https://cdn2.example.com',
    'https://cdn3.example.com'
  ];

  const fetchPromises = cdns.map(cdn =>
    fetch(`${cdn}${resourcePath}`).then(res => {
      if (!res.ok) throw new Error(`${cdn} failed`);
      return { cdn, response: res };
    })
  );

  try {
    const { cdn, response } = await Promise.any(fetchPromises);
    console.log(`Loaded from: ${cdn}`);
    return response;
  } catch (aggregateError) {
    console.error('All CDNs failed:', aggregateError.errors);
    throw new Error('Resource unavailable from all CDNs');
  }
}

loadFromCDN('/scripts/app.js').then(r => r.text());

Related Methods