乐闻世界logo
搜索文章和话题

What is the purpose of Promise.allSettled()? What is the difference from Promise.all()?

2月22日 14:07

Promise.allSettled() is a Promise static method introduced in ES2020 that allows us to wait for all Promises to complete (whether successful or failed) and returns the status and result of each Promise.

Basic Concept

Promise.allSettled() accepts an array of Promises as a parameter and returns a new Promise. This new Promise will complete only after all input Promises have completed (whether successful or failed), returning an array containing the status and result of each Promise.

Basic Usage

javascript
const promise1 = Promise.resolve(42); const promise2 = Promise.reject('Error occurred'); const promise3 = new Promise(resolve => setTimeout(() => resolve('Delayed completion'), 1000)); Promise.allSettled([promise1, promise2, promise3]) .then(results => { console.log(results); // Output: // [ // { status: 'fulfilled', value: 42 }, // { status: 'rejected', reason: 'Error occurred' }, // { status: 'fulfilled', value: 'Delayed completion' } // ] });

Return Value Structure

Each result object contains two properties:

  • status: 'fulfilled' (success) or 'rejected' (failure)
  • value: The value on success (only exists when status is 'fulfilled')
  • reason: The reason on failure (only exists when status is 'rejected')

Comparison with Promise.all()

Promise.all() - Fast Fail

javascript
const promise1 = Promise.resolve(1); const promise2 = Promise.reject('Error'); const promise3 = Promise.resolve(3); Promise.all([promise1, promise2, promise3]) .then(results => console.log(results)) .catch(error => console.error('Error:', error)); // Output: Error: Error // The result of promise3 cannot be obtained

Promise.allSettled() - Wait for All

javascript
const promise1 = Promise.resolve(1); const promise2 = Promise.reject('Error'); const promise3 = Promise.resolve(3); Promise.allSettled([promise1, promise2, promise3]) .then(results => { results.forEach(result => { if (result.status === 'fulfilled') { console.log('Success:', result.value); } else { console.error('Failure:', result.reason); } }); }); // Output: // Success: 1 // Failure: Error // Success: 3

Practical Use Cases

1. Batch Requests, Partial Failures Don't Affect Other Results

javascript
async function fetchMultipleUrls(urls) { const promises = urls.map(url => fetch(url).then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) ); const results = await Promise.allSettled(promises); const successful = results .filter(result => result.status === 'fulfilled') .map(result => result.value); const failed = results .filter(result => result.status === 'rejected') .map(result => result.reason); console.log('Successful requests:', successful.length); console.log('Failed requests:', failed.length); return { successful, failed }; } // Usage example const urls = [ 'https://api.example.com/users', 'https://api.example.com/posts', 'https://api.example.com/comments' ]; fetchMultipleUrls(urls).then(({ successful, failed }) => { console.log('Successful data:', successful); console.log('Failed reasons:', failed); });

2. Process Multiple Tasks in Parallel, Collect All Results

javascript
async function processTasks(tasks) { const results = await Promise.allSettled( tasks.map(task => task()) ); return results.map((result, index) => ({ task: tasks[index].name, status: result.status, result: result.status === 'fulfilled' ? result.value : result.reason })); } // Usage example const tasks = [ { name: 'Task 1', fn: () => Promise.resolve('Completed') }, { name: 'Task 2', fn: () => Promise.reject('Failed') }, { name: 'Task 3', fn: () => Promise.resolve('Completed') } ]; processTasks(tasks).then(results => { console.table(results); });

3. Image Loading, Display Successful and Failed Images

javascript
async function loadImages(imageUrls) { const imagePromises = imageUrls.map(url => { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve({ url, img }); img.onerror = () => reject(new Error(`Failed to load: ${url}`)); img.src = url; }); }); const results = await Promise.allSettled(imagePromises); const loadedImages = results .filter(result => result.status === 'fulfilled') .map(result => result.value); const failedUrls = results .filter(result => result.status === 'rejected') .map(result => result.reason.message); return { loadedImages, failedUrls }; } // Usage example const imageUrls = [ 'https://example.com/image1.jpg', 'https://example.com/image2.jpg', 'https://example.com/image3.jpg' ]; loadImages(imageUrls).then(({ loadedImages, failedUrls }) => { console.log('Successfully loaded images:', loadedImages); console.log('Failed to load images:', failedUrls); });

Error Handling

Handling Partial Failures

javascript
async function fetchWithPartialFailure(urls) { const results = await Promise.allSettled( urls.map(url => fetch(url)) ); const successfulRequests = results .filter(result => result.status === 'fulfilled') .map(result => result.value); const failedRequests = results .filter(result => result.status === 'rejected') .map(result => result.reason); if (failedRequests.length > 0) { console.warn('Some requests failed:', failedRequests); } return successfulRequests; }

Retrying Failed Requests

javascript
async function fetchWithRetry(urls, maxRetries = 3) { const results = await Promise.allSettled( urls.map(url => fetch(url)) ); const failedUrls = results .filter(result => result.status === 'rejected') .map((result, index) => urls[index]); if (failedUrls.length > 0) { console.log(`Retrying failed requests (${maxRetries} times)`); const retryResults = await Promise.allSettled( failedUrls.map(url => fetch(url)) ); // Handle retry results... } return results; }

Performance Considerations

1. Empty Array Handling

javascript
Promise.allSettled([]) .then(results => console.log(results)); // Output: []

2. Non-Promise Value Handling

javascript
Promise.allSettled([1, 2, Promise.resolve(3)]) .then(results => console.log(results)); // Output: // [ // { status: 'fulfilled', value: 1 }, // { status: 'fulfilled', value: 2 }, // { status: 'fulfilled', value: 3 } // ]

Comparison with Other Promise Methods

MethodBehaviorUse Case
Promise.all()All succeed or all failNeed all results to succeed
Promise.allSettled()Wait for all to complete, return all resultsNeed to know result of each operation
Promise.race()Return first completed resultNeed fastest result
Promise.any()Return first successful resultNeed any successful result

Best Practices

1. Check All Results

javascript
async function checkAllResults(promises) { const results = await Promise.allSettled(promises); const hasFailures = results.some(result => result.status === 'rejected'); if (hasFailures) { const failures = results .filter(result => result.status === 'rejected') .map(result => result.reason); console.error('Some operations failed:', failures); } return results; }

2. Aggregate Results

javascript
async function aggregateResults(promises) { const results = await Promise.allSettled(promises); return { total: results.length, successful: results.filter(r => r.status === 'fulfilled').length, failed: results.filter(r => r.status === 'rejected').length, results: results }; }

3. Provide Fallback

javascript
async function fetchWithFallback(urls, fallbackData) { const results = await Promise.allSettled( urls.map(url => fetch(url).then(r => r.json())) ); const data = results.map((result, index) => { if (result.status === 'fulfilled') { return result.value; } else { console.warn(`Request ${urls[index]} failed, using fallback data`); return fallbackData[index]; } }); return data; }

Browser Compatibility

Promise.allSettled() was introduced in ES2020 and is supported by modern browsers:

  • Chrome: 76+
  • Firefox: 71+
  • Safari: 13+
  • Edge: 79+

For older browsers, you can use a polyfill:

javascript
if (!Promise.allSettled) { Promise.allSettled = function(promises) { return Promise.all( promises.map(promise => Promise.resolve(promise).then( value => ({ status: 'fulfilled', value }), reason => ({ status: 'rejected', reason }) ) ) ); }; }

Summary

  1. Wait for all Promises to complete: Waits for all Promises to complete whether successful or failed
  2. Return detailed results: Returns the status and result of each Promise
  3. Suitable for partial failure scenarios: Use when some operations failing doesn't affect others
  4. Complementary to Promise.all(): Promise.all() fails fast, Promise.allSettled() waits for all
  5. Better error handling: Can handle each failed operation individually
  6. Polyfill support: Can be implemented with polyfill for older browsers
标签:Promise