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

Promise.allSettled() 的作用是什么?与 Promise.all() 有什么区别?

2月22日 14:07

Promise.allSettled() 是 ES2020 引入的 Promise 静态方法,它允许我们等待所有 Promise 完成(无论成功或失败),并返回每个 Promise 的状态和结果。

基本概念

Promise.allSettled() 接收一个 Promise 数组作为参数,返回一个新的 Promise。这个新的 Promise 会在所有输入的 Promise 都完成(无论成功或失败)后才完成,返回一个包含所有 Promise 状态和结果的数组。

基本用法

javascript
const promise1 = Promise.resolve(42); const promise2 = Promise.reject('出错了'); const promise3 = new Promise(resolve => setTimeout(() => resolve('延迟完成'), 1000)); Promise.allSettled([promise1, promise2, promise3]) .then(results => { console.log(results); // 输出: // [ // { status: 'fulfilled', value: 42 }, // { status: 'rejected', reason: '出错了' }, // { status: 'fulfilled', value: '延迟完成' } // ] });

返回值结构

每个结果对象包含两个属性:

  • status: 'fulfilled'(成功)或 'rejected'(失败)
  • value: 成功时的值(仅当 status 为 'fulfilled' 时存在)
  • reason: 失败时的原因(仅当 status 为 'rejected' 时存在)

与 Promise.all() 的对比

Promise.all() - 快速失败

javascript
const promise1 = Promise.resolve(1); const promise2 = Promise.reject('错误'); const promise3 = Promise.resolve(3); Promise.all([promise1, promise2, promise3]) .then(results => console.log(results)) .catch(error => console.error('错误:', error)); // 输出: 错误: 错误 // promise3 的结果无法获取

Promise.allSettled() - 等待全部

javascript
const promise1 = Promise.resolve(1); const promise2 = Promise.reject('错误'); const promise3 = Promise.resolve(3); Promise.allSettled([promise1, promise2, promise3]) .then(results => { results.forEach(result => { if (result.status === 'fulfilled') { console.log('成功:', result.value); } else { console.error('失败:', result.reason); } }); }); // 输出: // 成功: 1 // 失败: 错误 // 成功: 3

实际应用场景

1. 批量请求,部分失败不影响其他结果

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.length); console.log('失败的请求:', failed.length); return { successful, failed }; } // 使用示例 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); console.log('失败原因:', failed); });

2. 并行处理多个任务,收集所有结果

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 })); } // 使用示例 const tasks = [ { name: '任务1', fn: () => Promise.resolve('完成') }, { name: '任务2', fn: () => Promise.reject('失败') }, { name: '任务3', fn: () => Promise.resolve('完成') } ]; processTasks(tasks).then(results => { console.table(results); });

3. 图片加载,显示成功和失败的图片

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 }; } // 使用示例 const imageUrls = [ 'https://example.com/image1.jpg', 'https://example.com/image2.jpg', 'https://example.com/image3.jpg' ]; loadImages(imageUrls).then(({ loadedImages, failedUrls }) => { console.log('加载成功的图片:', loadedImages); console.log('加载失败的图片:', failedUrls); });

错误处理

处理部分失败

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('部分请求失败:', failedRequests); } return successfulRequests; }

重试失败的请求

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(`重试失败的请求 (${maxRetries} 次)`); const retryResults = await Promise.allSettled( failedUrls.map(url => fetch(url)) ); // 处理重试结果... } return results; }

性能考虑

1. 空数组处理

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

2. 非 Promise 值处理

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

与其他 Promise 方法的对比

方法行为使用场景
Promise.all()全部成功才成功,一个失败就失败需要所有结果都成功
Promise.allSettled()等待全部完成,返回所有结果需要知道每个操作的结果
Promise.race()返回第一个完成的结果需要最快的结果
Promise.any()返回第一个成功的结果需要任何一个成功的结果

最佳实践

1. 检查所有结果

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('部分操作失败:', failures); } return results; }

2. 聚合结果

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. 提供降级方案

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(`请求 ${urls[index]} 失败,使用降级数据`); return fallbackData[index]; } }); return data; }

浏览器兼容性

Promise.allSettled() 是 ES2020 引入的,现代浏览器都支持:

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

对于旧浏览器,可以使用 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 }) ) ) ); }; }

总结

  1. 等待所有 Promise 完成:无论成功或失败,都会等待所有 Promise 完成
  2. 返回详细结果:每个 Promise 的状态和结果都会被返回
  3. 适合部分失败场景:当某些操作失败不影响其他操作时使用
  4. 与 Promise.all() 互补:Promise.all() 快速失败,Promise.allSettled() 等待全部
  5. 提供更好的错误处理:可以针对每个失败的操作进行单独处理
  6. 支持 polyfill:旧浏览器可以通过 polyfill 实现兼容
标签:Promise