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