Promise.allSettled() 是 ES2020 引入的 Promise 静态方法,它允许我们等待所有 Promise 完成(无论成功或失败),并返回每个 Promise 的状态和结果。
基本概念
Promise.allSettled() 接收一个 Promise 数组作为参数,返回一个新的 Promise。这个新的 Promise 会在所有输入的 Promise 都完成(无论成功或失败)后才完成,返回一个包含所有 Promise 状态和结果的数组。
基本用法
javascriptconst 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() - 快速失败
javascriptconst 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() - 等待全部
javascriptconst 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. 批量请求,部分失败不影响其他结果
javascriptasync 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. 并行处理多个任务,收集所有结果
javascriptasync 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. 图片加载,显示成功和失败的图片
javascriptasync 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); });
错误处理
处理部分失败
javascriptasync 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; }
重试失败的请求
javascriptasync 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. 空数组处理
javascriptPromise.allSettled([]) .then(results => console.log(results)); // 输出: []
2. 非 Promise 值处理
javascriptPromise.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. 检查所有结果
javascriptasync 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. 聚合结果
javascriptasync 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. 提供降级方案
javascriptasync 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:
javascriptif (!Promise.allSettled) { Promise.allSettled = function(promises) { return Promise.all( promises.map(promise => Promise.resolve(promise).then( value => ({ status: 'fulfilled', value }), reason => ({ status: 'rejected', reason }) ) ) ); }; }
总结
- 等待所有 Promise 完成:无论成功或失败,都会等待所有 Promise 完成
- 返回详细结果:每个 Promise 的状态和结果都会被返回
- 适合部分失败场景:当某些操作失败不影响其他操作时使用
- 与 Promise.all() 互补:Promise.all() 快速失败,Promise.allSettled() 等待全部
- 提供更好的错误处理:可以针对每个失败的操作进行单独处理
- 支持 polyfill:旧浏览器可以通过 polyfill 实现兼容