Understanding JavaScript Promise.any(): A Complete Guide

JavaScript’s Promise.any() is a powerful method introduced in ES2021 that helps manage multiple promises in a unique way. Unlike its cousins Promise.all() and Promise.race(), Promise.any() fulfills when any of the input promises fulfill, making it particularly useful for scenarios where you want to work with the first successful result.

In this comprehensive guide, we’ll explore Promise.any(), understand its use cases, and learn how to implement it effectively in your JavaScript applications.

Table of Contents

How Promise.any() Works

Promise.any() takes an iterable of Promise objects and returns a single Promise. This returned promise fulfills when any of the input’s promises fulfills, with the value of the fulfilled promise. If all promises are rejected, it throws an AggregateError.

Basic Syntax

Promise.any(iterable)
Code language: JavaScript (javascript)

Simple Example

const promises = [
  fetch('https://api.example.com/endpoint1'),
  fetch('https://api.example.com/endpoint2'),
  fetch('https://api.example.com/endpoint3')
];

Promise.any(promises)
  .then(firstSuccess => console.log('First success:', firstSuccess))
  .catch(error => console.log('All promises failed:', error));
Code language: JavaScript (javascript)

Key Features of Promise.any()

1. First Fulfillment Wins

The most distinctive feature of Promise.any() is that it resolves with the first promise that fulfills, ignoring any rejections unless all promises reject.

const promises = [
  Promise.reject('Error 1'),
  Promise.resolve('Success!'),
  Promise.reject('Error 2')
];

Promise.any(promises)
  .then(result => console.log(result))  // Outputs: 'Success!'
  .catch(error => console.log(error));
Code language: JavaScript (javascript)

2. AggregateError Handling

When all promises reject, Promise.any() throws an AggregateError containing all rejection reasons.

const promises = [
  Promise.reject('Error 1'),
  Promise.reject('Error 2'),
  Promise.reject('Error 3')
];

Promise.any(promises)
  .then(result => console.log(result))
  .catch(error => {
    console.log(error.name);      // AggregateError
    console.log(error.errors);    // ['Error 1', 'Error 2', 'Error 3']
  });
Code language: JavaScript (javascript)

Practical Use Cases

1. Resource Loading with Fallbacks

const loadImage = src => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
};

const images = [
  loadImage('/path/to/image1.jpg'),
  loadImage('/path/to/image2.jpg'),
  loadImage('/path/to/image3.jpg')
];

Promise.any(images)
  .then(firstLoadedImage => document.body.appendChild(firstLoadedImage))
  .catch(error => console.log('All images failed to load'));
Code language: JavaScript (javascript)

2. API Race with Timeout

const fetchWithTimeout = (url, timeout = 5000) => {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  return fetch(url, { signal: controller.signal })
    .finally(() => clearTimeout(timeoutId));
};

const apis = [
  fetchWithTimeout('https://api1.example.com/data'),
  fetchWithTimeout('https://api2.example.com/data'),
  fetchWithTimeout('https://api3.example.com/data')
];

Promise.any(apis)
  .then(response => response.json())
  .then(data => console.log('First successful response:', data))
  .catch(error => console.log('All APIs failed'));
Code language: JavaScript (javascript)

Promise.any() vs Other Promise Methods

Comparison with Promise.race()

While Promise.race() settles with the first promise that settles (either fulfills or rejects), Promise.any() waits for the first fulfillment:

// Promise.race() example
Promise.race([
  Promise.reject('Error'),
  Promise.resolve('Success')
])
  .then(console.log)
  .catch(console.error);  // Logs: Error

// Promise.any() example
Promise.any([
  Promise.reject('Error'),
  Promise.resolve('Success')
])
  .then(console.log)      // Logs: Success
  .catch(console.error);
Code language: JavaScript (javascript)

Comparison with Promise.all()

Unlike Promise.all() which requires all promises to fulfill, Promise.any() needs only one fulfillment:

const promises = [
  Promise.resolve(1),
  Promise.reject('Error'),
  Promise.resolve(3)
];

Promise.all(promises)
  .then(console.log)
  .catch(console.error);  // Logs: Error

Promise.any(promises)
  .then(console.log)      // Logs: 1
  .catch(console.error);
Code language: JavaScript (javascript)

Best Practices

1. Always Handle Errors

Promise.any(promises)
  .then(result => {
    // Handle success
  })
  .catch(error => {
    if (error instanceof AggregateError) {
      console.log('All promises rejected:', error.errors);
    } else {
      console.log('Unexpected error:', error);
    }
  });
Code language: JavaScript (javascript)

2. Consider Performance Implications

const optimizedPromises = promises.map(promise => {
  return new Promise((resolve, reject) => {
    promise
      .then(resolve)
      .catch(reject)
      .finally(() => {
        // Cleanup resources if needed
      });
  });
});
Code language: JavaScript (javascript)

Browser Support and Polyfills

Promise.any() is relatively new, so you might need a polyfill for older browsers. Here’s a simple polyfill implementation:

if (!Promise.any) {
  Promise.any = function(promises) {
    return new Promise((resolve, reject) => {
      let errors = [];
      let rejected = 0;
      
      promises.forEach((promise, index) => {
        Promise.resolve(promise)
          .then(resolve)
          .catch(error => {
            errors[index] = error;
            rejected++;
            if (rejected === promises.length) {
              reject(new AggregateError(errors, 'All promises rejected'));
            }
          });
      });
    });
  };
}
Code language: JavaScript (javascript)

Conclusion

Promise.any() is a valuable addition to JavaScript’s promise toolkit, perfect for scenarios where you need the first successful result from multiple asynchronous operations. Its ability to handle multiple promises and provide meaningful error information through AggregateError makes it a powerful tool for modern web development.

For more information about handling promises in JavaScript, check out our guide on JavaScript Promise.race() and JavaScript Promise Methods, which cover other essential promise methods in detail.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share via
Copy link
Powered by Social Snap