Learnitweb

Promise.any()

Revisiting the problem with Promise.race()

Suppose Eugene answers in 1 second, but he doesn’t have a pen. John and Susie respond later, but they do have pens.

Since Promise.race() reacts to the first settled promise, the final result becomes a rejection.

Here’s how that situation looks in code:

function askJohn() {
    return new Promise(resolve => {
        setTimeout(() => resolve("John: I have a pen"), 3000);
    });
}

function askEugene() {
    return new Promise((resolve, reject) => {
        setTimeout(() => reject("Eugene: Sorry, I don't have a pen"), 1000);
    });
}

function askSusie() {
    return new Promise(resolve => {
        setTimeout(() => resolve("Susie: I have a pen"), 2000);
    });
}

Promise.race([
    askJohn(),
    askEugene(),
    askSusie()
])
.then(result => console.log(result))
.catch(error => console.log(error));

Output:

Eugene: Sorry, I don't have a pen

Even though Susie could help, Promise.race() ends as soon as Eugene responds.

Why this is a problem

In real life, you wouldn’t stop asking just because one person said “no.”
You would simply wait a little longer and take help from someone else.

This is exactly the limitation of Promise.race().

What we really want is:

  • Ignore failed promises
  • Wait until at least one promise succeeds
  • Only fail if all promises fail

And that’s where Promise.any() comes in.

Introducing Promise.any()

Promise.any() returns a promise that:

  • Resolves when the first promise fulfills
  • Ignores rejected promises
  • Rejects only if all promises are rejected

This makes it perfect for situations where success matters more than speed.

Using Promise.any() with our example

Let’s replace Promise.race() with Promise.any():

Promise.any([
    askJohn(),
    askEugene(),
    askSusie()
])
.then(result => {
    console.log(result);
});

Now the behavior changes.

Even though Eugene fails first, Promise.any() ignores that failure and waits for the next successful promise.

Output:

Susie: I have a pen

This is exactly what we want.

How Promise.any() behaves internally

When you call Promise.any():

  • All promises start executing at the same time
  • Rejected promises are ignored
  • As soon as one promise fulfills, the result is returned
  • Remaining promises are ignored

This makes it ideal for fallback logic.

What if all promises fail?

This is the only situation where Promise.any() rejects.

Let’s modify all functions so they reject:

function askJohn() {
    return Promise.reject("John: No pen");
}

function askEugene() {
    return Promise.reject("Eugene: No pen");
}

function askSusie() {
    return Promise.reject("Susie: No pen");
}

Promise.any([
    askJohn(),
    askEugene(),
    askSusie()
])
.then(result => console.log(result))
.catch(error => {
    console.log(error);
});

This time, the promise gets rejected.

The rejection is not a normal error — it’s an AggregateError.

Understanding AggregateError

AggregateError is a special error type that holds multiple errors.

Inside it, you’ll find an errors array containing all rejection reasons, in the same order as the promises passed in.

For example:

error.errors

might contain:

[
  "John: No pen",
  "Eugene: No pen",
  "Susie: No pen"
]

This makes debugging much easier because you can see why everything failed.

What if the array is empty?

If you pass an empty array:

Promise.any([])
    .then(result => console.log(result))
    .catch(error => console.log(error));

The promise is immediately rejected with an AggregateError, because there is no possible way to get a fulfilled result.


What if you pass non-promise values?

Just like other promise utilities, non-promise values are treated as already resolved.

Promise.any([10, 20, 30])
    .then(result => console.log(result));

Output:

10

The first value is immediately considered fulfilled.


When should you use Promise.any()?

You should use it when:

  • You only care about the first successful result
  • Failures are acceptable
  • You want a fallback mechanism
  • You are querying multiple sources and only need one valid response

Examples include:

  • Multiple APIs serving the same data
  • Redundant services
  • Fallback servers or caches