Hack Frontend Community

Promise.all, Promise.race, Promise.allSettled, Promise.any

Promise Static Methods

JavaScript provides four main static methods for working with multiple promises simultaneously:

  • Promise.all()
  • Promise.race()
  • Promise.allSettled()
  • Promise.any()

Each solves different tasks. Let's examine them in detail.


Promise.all()

Waits for all promises to fulfill. If at least one is rejected — the entire result is rejected.

Syntax

Promise.all(iterable)

Behavior

  • ✅ Returns array of results if all promises are fulfilled successfully
  • ❌ Rejects with error of the first rejected promise
  • Order of results corresponds to order of promises

Successful Execution Example

const promise1 = Promise.resolve(10);
const promise2 = Promise.resolve(20);
const promise3 = Promise.resolve(30);

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results);  // [10, 20, 30]
  });

Rejection Example

const promise1 = Promise.resolve(10);
const promise2 = Promise.reject('Error!');
const promise3 = Promise.resolve(30);

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results);
  })
  .catch(error => {
    console.log(error);  // "Error!"
    // promise3 will be ignored
  });

When to use?

  • Loading multiple independent resources simultaneously
  • All requests are required to continue work
  • Need to wait for all operations to complete
async function loadUserData(userId) {
  const [user, posts, comments] = await Promise.all([
    fetchUser(userId),
    fetchPosts(userId),
    fetchComments(userId)
  ]);
  
  return { user, posts, comments };
}

Important:

If one promise rejects, other promises continue executing, but their results will be ignored.


Promise.race()

Returns the result of the first settled promise (successfully or with error).

Syntax

Promise.race(iterable)

Behavior

  • Completes as soon as any promise settles
  • Returns result or error of the first settled promise
  • Other promises are ignored

Example

const slow = new Promise(resolve => {
  setTimeout(() => resolve('Slow'), 2000);
});

const fast = new Promise(resolve => {
  setTimeout(() => resolve('Fast'), 500);
});

Promise.race([slow, fast])
  .then(result => {
    console.log(result);  // "Fast"
  });

Error Example

const success = new Promise(resolve => {
  setTimeout(() => resolve('Success'), 2000);
});

const failure = new Promise((resolve, reject) => {
  setTimeout(() => reject('Error'), 500);
});

Promise.race([success, failure])
  .then(result => console.log(result))
  .catch(error => console.log(error));  // "Error"

When to use?

  • Timeouts: cancel operation if it takes too long
  • Fallbacks: try multiple data sources
  • Request racing: use the fastest response
// Request timeout
function fetchWithTimeout(url, timeout = 5000) {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
}

fetchWithTimeout('/api/data', 3000)
  .then(response => response.json())
  .catch(error => console.error(error));

Promise.allSettled()

Waits for all promises to settle (successfully or with error) and returns their statuses.

Syntax

Promise.allSettled(iterable)

Behavior

  • ✅ Always resolves (never rejects)
  • Returns array of objects with results of each promise
  • Each object contains status and value / reason

Result Format

[
  { status: 'fulfilled', value: result },
  { status: 'rejected', reason: error }
]

Example

const promises = [
  Promise.resolve(10),
  Promise.reject('Error'),
  Promise.resolve(30)
];

Promise.allSettled(promises)
  .then(results => {
    console.log(results);
    /*
    [
      { status: 'fulfilled', value: 10 },
      { status: 'rejected', reason: 'Error' },
      { status: 'fulfilled', value: 30 }
    ]
    */
  });

Processing Results

const results = await Promise.allSettled([
  fetch('/api/users'),
  fetch('/api/posts'),
  fetch('/api/comments')
]);

const successful = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value);

const failed = results
  .filter(r => r.status === 'rejected')
  .map(r => r.reason);

console.log('Successful:', successful.length);
console.log('Failed:', failed.length);

When to use?

  • Need results of all operations, even if some failed
  • Data aggregation from multiple sources
  • Partial data loading (show what loaded)
async function loadDashboard() {
  const [userResult, statsResult, notificationsResult] = await Promise.allSettled([
    fetchUser(),
    fetchStats(),
    fetchNotifications()
  ]);
  
  return {
    user: userResult.status === 'fulfilled' ? userResult.value : null,
    stats: statsResult.status === 'fulfilled' ? statsResult.value : null,
    notifications: notificationsResult.status === 'fulfilled' 
      ? notificationsResult.value 
      : []
  };
}

ES2020:

Promise.allSettled() was added in ES2020 and is supported by all modern browsers.


Promise.any()

Returns the first successfully fulfilled promise. Rejects only if all promises are rejected.

Syntax

Promise.any(iterable)

Behavior

  • ✅ Resolves with result of first successful promise
  • ❌ Rejects only if all promises are rejected (with AggregateError)
  • Ignores rejected promises as long as there's at least one successful

Example

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

Promise.any(promises)
  .then(result => {
    console.log(result);  // "Success!"
  });

Complete Rejection Example

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

Promise.any(promises)
  .catch(error => {
    console.log(error);  // AggregateError: All promises were rejected
    console.log(error.errors);  // ['Error 1', 'Error 2', 'Error 3']
  });

When to use?

  • Fallbacks: try multiple data sources
  • Need at least one successful result
  • Working with unreliable APIs (try multiple servers)
// Load image from backup servers
async function loadImage(imageName) {
  const servers = [
    `https://cdn1.example.com/${imageName}`,
    `https://cdn2.example.com/${imageName}`,
    `https://cdn3.example.com/${imageName}`
  ];
  
  try {
    const imageUrl = await Promise.any(
      servers.map(url => fetch(url).then(r => {
        if (!r.ok) throw new Error('Failed');
        return url;
      }))
    );
    return imageUrl;
  } catch (error) {
    console.error('All servers unavailable');
  }
}

ES2021:

Promise.any() was added in ES2021.


Comparison Table

MethodSettles whenSuccess resultError result
Promise.allAll fulfilled OR first rejectedArray of all resultsFirst error
Promise.raceFirst settledFirst resultFirst error
Promise.allSettledAll settledArray of {status, value/reason}Never rejects
Promise.anyFirst fulfilled OR all rejectedFirst successful resultAggregateError

Practical Examples

Loading with Timeout and Retry

async function fetchWithRetry(url, retries = 3, timeout = 5000) {
  for (let i = 0; i < retries; i++) {
    try {
      const result = await Promise.race([
        fetch(url),
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error('Timeout')), timeout)
        )
      ]);
      return result;
    } catch (error) {
      if (i === retries - 1) throw error;
      console.log(`Attempt ${i + 1} failed, retrying...`);
    }
  }
}

Parallel Loading with Limit

async function fetchWithLimit(urls, limit = 3) {
  const results = [];
  const executing = [];
  
  for (const url of urls) {
    const promise = fetch(url).then(r => r.json());
    results.push(promise);
    
    if (limit <= urls.length) {
      const executing_promise = promise.then(() => 
        executing.splice(executing.indexOf(executing_promise), 1)
      );
      executing.push(executing_promise);
      
      if (executing.length >= limit) {
        await Promise.race(executing);
      }
    }
  }
  
  return Promise.all(results);
}

Partial Data Loading

async function loadPageData() {
  const results = await Promise.allSettled([
    fetchCriticalData(),    // Required data
    fetchOptionalWidget1(), // Optional widgets
    fetchOptionalWidget2(),
    fetchOptionalWidget3()
  ]);
  
  // If critical data didn't load - show error
  if (results[0].status === 'rejected') {
    throw new Error('Failed to load page');
  }
  
  return {
    critical: results[0].value,
    widgets: results.slice(1)
      .filter(r => r.status === 'fulfilled')
      .map(r => r.value)
  };
}

Conclusion

  • Promise.all() — all or nothing (parallel loading of required data)
  • Promise.race() — first wins (timeouts, request racing)
  • Promise.allSettled() — result of each (partial loading, aggregation)
  • Promise.any() — first successful (backup servers, fallback)

In Interviews:

Common questions:

  • What's the difference between Promise.all and Promise.allSettled?
  • When to use Promise.race vs Promise.any?
  • What happens if you pass an empty array to each method?
  • How to handle partial errors when loading data?