Understanding Promise.any() behavior in Javascript

Promises are a powerful tool in JavaScript used for handling asynchronous operations. Introduced in ES6, promises provide a cleaner way to write asynchronous code compared to traditional callbacks.

In ES2021, a new addition was made to promises called Promise.any(). This method allows you to handle a collection of promises and returns a new promise that is fulfilled as soon as any of the input promises resolve successfully. In this article, we will dive into understanding the behavior of Promise.any().

Basic Usage

The basic syntax of Promise.any() is as follows:

Promise.any(iterable)
  .then(result => {
    // handle the result
  })
  .catch(error => {
    // handle the error
  });

The iterable parameter represents an iterable collection of promises, such as an array. When Promise.any() is invoked, it returns a promise that is resolved as soon as any of the input promises are resolved. The resulting promise will contain the value of the first resolved promise.

Resolving Values

Promise.any() behaves differently from Promise.race(), which returns the first resolved or rejected promise. With Promise.any(), even if one of the promises is rejected, the method will still resolve when the first promise is resolved.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'Promise 1');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 200, 'Promise 2');
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 300, 'Promise 3');
});

Promise.any([promise1, promise2, promise3])
  .then(result => {
    console.log(result); // Output: Promise 1
  })
  .catch(error => {
    // This block won't be executed as at least one promise resolved successfully
  });

In the example above, Promise.any() is used to handle an array of three promises. Even though promise2 and promise3 have a longer delay, the method resolves with the value from promise1, as it resolves earlier.

Handling Errors

If all of the input promises are rejected, Promise.any() will reject with an AggregateError containing all the rejection reasons. This behavior is different from Promise.race(), which only returns the rejection reason of the first rejected promise.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, 'Promise 1 rejected');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 200, 'Promise 2 rejected');
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(reject, 300, 'Promise 3 rejected');
});

Promise.any([promise1, promise2, promise3])
  .then(result => {
    // This block won't be executed as at least one promise needs to resolve
  })
  .catch(errors => {
    console.log(errors); 
    // Output: AggregateError: All promises were rejected
    // Contains all the rejection reasons in an array
  });

In the above example, none of the promises resolve successfully, so Promise.any() rejects with an AggregateError containing the reasons for rejection from all the promises.

Browser Support

It’s important to note that Promise.any() is not supported in all browsers. As of July 2021, it is supported by Chrome, Firefox, and Safari but not by Internet Explorer or Microsoft Edge. To use Promise.any() in unsupported environments, you can consider using a polyfill like promise-any.

Conclusion

Promise.any() provides a convenient way to handle a collection of promises and retrieve the value of the first resolved promise. However, keep in mind that it behaves differently from Promise.race() and returns an AggregateError when all the input promises are rejected. Understanding the behavior of Promise.any() allows you to write more efficient and reliable asynchronous code in JavaScript.

Tags: JavaScript, Promises, Asynchronous Programming