For AI agents: the complete documentation index is available at /tc39-atlas/en/llms.txt, the full documentation bundle is available at /tc39-atlas/en/llms-full.txt, and this page is available as Markdown at /tc39-atlas/en/proposals/proposal-promise-any.md.
  • English
  • Promise.any S4

    Proposal details
    Proposal overview

    The proposal introduces Promise.any, which fulfills with the first fulfilled promise from an iterable, or rejects with an AggregateError if all reject. It also adds the AggregateError class.

    Note

    The README below comes from the upstream repository and may contain outdated stage or status metadata. Use the proposal details above as the current source of truth.

    ECMAScript proposal: Promise.any + AggregateError

    Author: Mathias Bynens, Kevin Gibbons, Sergey Rubanov

    Champion: Mathias Bynens

    Stage: Stage 4 of the TC39 process.

    Motivation

    There are four main combinators in the Promise landscape.

    namedescription
    Promise.allSettleddoes not short-circuitadded in ES2020 ✅
    Promise.allshort-circuits when an input value is rejectedadded in ES2015 ✅
    Promise.raceshort-circuits when an input value is settledadded in ES2015 ✅
    Promise.anyshort-circuits when an input value is fulfilledthis proposal 🆕 scheduled for ES2021

    These are all commonly available in userland promise libraries, and they’re all independently useful, each one serving different use cases.

    Proposed solution

    Promise.any accepts an iterable of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an AggregateError holding the rejection reasons if all of the given promises are rejected. (If something more fundamental goes wrong, e.g. iterating over the iterable results in an exception, Promise.any returns a rejected promise with that exception.)

    High-level API

    try {
      const first = await Promise.any(promises);
      // Any of the promises was fulfilled.
    } catch (error) {
      // All of the promises were rejected.
    }

    Or, without async/await:

    Promise.any(promises).then(
      (first) => {
        // Any of the promises was fulfilled.
      },
      (error) => {
        // All of the promises were rejected.
      }
    );

    In the above examples, error is an AggregateError, a new Error subclass that groups together individual errors. Every AggregateError instance contains a pointer to an array of exceptions.

    FAQ

    Why choose the name any?

    It clearly describes what it does, and there’s precedent for the name any in userland libraries offering this functionality:

    Why throw an AggregateError instead of an array?

    The prevailing practice within the ECMAScript language is to only throw exception types. Existing code in the ecosystem likely relies on the fact that currently, all exceptions thrown by built-in methods and syntax are instanceof Error. Adding a new language feature that can throw a plain array would break that invariant, and could be a web compatibility issue. Additionally, by using an Error instance (or a subclass), a stack trace can be provided — something that’s easy to discard if not needed, but impossible to obtain later if it is needed.

    Illustrative examples

    This snippet checks which endpoint responds the fastest, and then logs it.

    Promise.any([
      fetch('https://v8.dev/').then(() => 'home'),
      fetch('https://v8.dev/blog').then(() => 'blog'),
      fetch('https://v8.dev/docs').then(() => 'docs')
    ]).then((first) => {
      // Any of the promises was fulfilled.
      console.log(first);
      // → 'home'
    }).catch((error) => {
      // All of the promises were rejected.
      console.log(error);
    });

    TC39 meeting notes

    Specification

    Implementations