ECMAScript 2021 introduces Promise.any() method

ECMAScript 2021 introduces Promise.any() method

ECMAScript 2021 is the latest JavaScript version that introduced multiple new features to the JavaScript language.

In this blog, we will cover Promise.any() method that was a part of ECMAScript 2021 addition.

Promise.any() method accepts a list of Promise objects as an iterable object and, as soon as one of the promises from the list fulfills, it returns a single promise that resolves with the value from that promise.

If no promise in the iterable is fulfilled, then the returned promise is rejected with an AggregateError, which is a new subclass of the Error.

Let’s take an example to understand it better.

const promise1 = fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(
    (response) => response.json()
  );

const promise2 = fetch("https://jsonplaceholder.typicode.com/todos/2")
  .then(
    (response) => response.json()
  );

const promise3 = fetch("https://jsonplaceholder.typicode.com/todos/3")
  .then(
    (response) => response.json()
  );

Promise.any([promise1, promise2, promise3])
  .then((value) =>console.log(value))
  .catch((error) => console.log(error))

//Output
{
  completed: false,
  id: 1,
  title: "delectus aut autem",
  userId: 1
}

In the above example, we are passing three different promises to Promise.any() method for fetching a todo item using a fake API.

promise1 is the first promise to be fulfilled so its value (a todo object) is returned from the Promise.any() method and printed to the console.

Syntax:

Promise.any(iterable);

Return value:

  • An already rejected Promise, if the iterable passed, is empty.
Promise.any([]);

//Output
Promise {<rejected>: AggregateError: All promises were rejected}
  • An asynchronously resolved Promise, if the iterable passed, contains no promises.
Promise.any([100,200,300]);

//Output
Promise {<fulfilled>: 100}
  • First resolved value, if any of the promises in the given iterable resolves.
const promiseError = new Promise((resolve, reject) => {
  reject("Error coming!");
});

const promiseSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "Slow as a tortoise");
});

const promiseFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "Fast as a bullet");
});

Promise.any([promiseError, promiseSlow, promiseFast])
.then((value) => {
  console.log(value);
});

//Output "Fast as a bullet"
  • Error if all the promises are rejected.
const pErr1 = new Promise((resolve, reject) => {
  reject("Always fails");
});

const pErr2 = new Promise((resolve, reject) => {
  reject("I will also fail");
});

Promise.any([pErr1, pErr2]).catch((err) => {
  console.log(err);
});

//Output
AggregateError: All promises were rejected
Promise {<fulfilled>: undefined}

Promise.race vs Promise.any

Promise.race() returns the first settled value (either fulfillment or rejection) from a list of promises while the Promise.any() returns the first fulfilled value.

Let’s take an example to understand it better.

const promise1 = fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(
  (response) => response.json()
);

const promise2 = new Promise((resolve, reject) => {
  reject("I am a rejected value");
});

Promise.race([promise1, promise2])
  .then((value) => console.log(value))
  .catch((value) => console.log(value));

//Output "I am a rejected value"

Promise.any([promise1, promise2])
  .then((value) => console.log(value))
  .catch((value) => console.log(value));

//Output
{
  completed: false,
  id: 1,
  title: "delectus aut autem",
  userId: 1
}

In the above example, promise1 will fetch a todo item from an endpoint but, promise2 will be instantly rejected.

As we know, Promise.race() returns the first promise that is either resolved or rejected from a list of promises, so the value of promise2 is returned as it is instantly rejected.

But, in the case of Promise.any(), the first resolved value is returned, so we get a todo object as an output.