Promise.any() 的作用是什么?
Promise.any() 是 ES2021 引入的 Promise 静态方法,它接收一个 Promise 数组,返回第一个成功完成的 Promise 的结果。如果所有 Promise 都失败,则返回 AggregateError。基本概念Promise.any() 接收一个可迭代的 Promise 对象作为参数,返回一个新的 Promise。这个新的 Promise 会在第一个 Promise 成功完成时立即完成,返回该 Promise 的结果。如果所有 Promise 都失败,则返回一个 AggregateError,包含所有失败的原因。基本用法const promise1 = Promise.reject('错误1');const promise2 = Promise.reject('错误2');const promise3 = Promise.resolve('成功');Promise.any([promise1, promise2, promise3]) .then(result => { console.log(result); // 输出: 成功 }) .catch(error => { console.error(error); });与其他方法的对比Promise.any() vs Promise.race()Promise.any(): 返回第一个成功的 Promiseconst promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.resolve('另一个成功');Promise.any([promise1, promise2, promise3]) .then(result => console.log(result)); // 输出: 成功Promise.race(): 返回第一个完成的 Promise(无论成功或失败)const promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.resolve('另一个成功');Promise.race([promise1, promise2, promise3]) .then(result => console.log(result)) .catch(error => console.error(error)); // 输出: 错误1Promise.any() vs Promise.all()Promise.any(): 只要有一个成功就返回const promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.reject('错误3');Promise.any([promise1, promise2, promise3]) .then(result => console.log(result)); // 输出: 成功Promise.all(): 必须全部成功才返回const promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.reject('错误3');Promise.all([promise1, promise2, promise3]) .then(result => console.log(result)) .catch(error => console.error(error)); // 输出: 错误1Promise.any() vs Promise.allSettled()Promise.any(): 返回第一个成功的结果const promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.reject('错误3');Promise.any([promise1, promise2, promise3]) .then(result => console.log(result)); // 输出: 成功Promise.allSettled(): 返回所有 Promise 的状态const promise1 = Promise.reject('错误1');const promise2 = Promise.resolve('成功');const promise3 = Promise.reject('错误3');Promise.allSettled([promise1, promise2, promise3]) .then(results => console.log(results));// 输出:// [// { status: 'rejected', reason: '错误1' },// { status: 'fulfilled', value: '成功' },// { status: 'rejected', reason: '错误3' }// ]AggregateError当所有 Promise 都失败时,Promise.any() 会返回一个 AggregateError,包含所有失败的原因。基本用法const promise1 = Promise.reject('错误1');const promise2 = Promise.reject('错误2');const promise3 = Promise.reject('错误3');Promise.any([promise1, promise2, promise3]) .catch(error => { console.error(error instanceof AggregateError); // true console.error(error.message); // All promises were rejected console.error(error.errors); // ['错误1', '错误2', '错误3'] });处理 AggregateErrorasync function fetchFromMultipleSources(urls) { try { const response = await Promise.any( urls.map(url => fetch(url)) ); return await response.json(); } catch (error) { if (error instanceof AggregateError) { console.error('所有数据源都失败了:'); error.errors.forEach((err, index) => { console.error(` ${urls[index]}: ${err.message}`); }); throw new Error('无法从任何数据源获取数据'); } throw error; }}实际应用场景1. 从多个数据源获取数据,使用最快成功的async function fetchFromFastestSource(sources) { try { const response = await Promise.any( sources.map(source => fetch(source.url)) ); return await response.json(); } catch (error) { if (error instanceof AggregateError) { console.error('所有数据源都失败了'); throw new Error('无法获取数据'); } throw error; }}// 使用示例const sources = [ { name: '主服务器', url: 'https://api1.example.com/data' }, { name: '备用服务器1', url: 'https://api2.example.com/data' }, { name: '备用服务器2', url: 'https://api3.example.com/data' }];fetchFromFastestSource(sources) .then(data => console.log('数据:', data)) .catch(error => console.error(error));2. 实现超时机制function fetchWithTimeout(url, timeout = 5000) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Timeout')), timeout); }); return Promise.any([ fetch(url).then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }), timeoutPromise ]);}// 使用示例fetchWithTimeout('/api/data', 3000) .then(data => console.log('数据:', data)) .catch(error => { if (error.message === 'Timeout') { console.error('请求超时'); } else { console.error('请求失败:', error); } });3. 尝试多个备份方案async function tryMultipleStrategies(strategies) { try { return await Promise.any( strategies.map(strategy => strategy()) ); } catch (error) { if (error instanceof AggregateError) { console.error('所有策略都失败了'); throw new Error('无法完成任务'); } throw error; }}// 使用示例const strategies = [ () => fetch('/api/v1/data').then(r => r.json()), () => fetch('/api/v2/data').then(r => r.json()), () => fetch('/api/v3/data').then(r => r.json())];tryMultipleStrategies(strategies) .then(data => console.log('数据:', data)) .catch(error => console.error(error));4. 图片加载,使用第一个成功加载的async function loadFirstSuccessfulImage(imageUrls) { try { const imagePromises = imageUrls.map(url => { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = () => reject(new Error(`Failed to load: ${url}`)); img.src = url; }); }); return await Promise.any(imagePromises); } catch (error) { if (error instanceof AggregateError) { console.error('所有图片都加载失败'); throw new Error('无法加载图片'); } throw error; }}// 使用示例const imageUrls = [ 'https://cdn1.example.com/image.jpg', 'https://cdn2.example.com/image.jpg', 'https://cdn3.example.com/image.jpg'];loadFirstSuccessfulImage(imageUrls) .then(img => document.body.appendChild(img)) .catch(error => console.error(error));错误处理处理所有失败的情况async function fetchWithFallback(urls) { try { const response = await Promise.any( urls.map(url => fetch(url)) ); return await response.json(); } catch (error) { if (error instanceof AggregateError) { console.error('所有 URL 都失败了'); // 可以返回默认值或重新抛出错误 return { error: 'All sources failed' }; } throw error; }}记录所有失败的原因async function fetchWithLogging(urls) { try { const response = await Promise.any( urls.map(url => fetch(url)) ); return await response.json(); } catch (error) { if (error instanceof AggregateError) { console.error('所有 URL 都失败了:'); error.errors.forEach((err, index) => { console.error(` ${urls[index]}: ${err.message}`); }); throw new Error('无法获取数据'); } throw error; }}性能考虑空数组处理Promise.any([]) .then(result => console.log(result)) .catch(error => { console.error(error instanceof AggregateError); // true console.error(error.errors); // [] });非 Promise 值处理Promise.any([1, 2, Promise.resolve(3)]) .then(result => console.log(result)); // 输出: 1浏览器兼容性Promise.any() 是 ES2021 引入的,现代浏览器都支持:Chrome: 85+Firefox: 79+Safari: 14+Edge: 85+对于旧浏览器,可以使用 polyfill:if (!Promise.any) { Promise.any = function(promises) { return new Promise((resolve, reject) => { const errors = []; let rejectedCount = 0; promises.forEach((promise, index) => { Promise.resolve(promise).then( value => resolve(value), error => { errors[index] = error; rejectedCount++; if (rejectedCount === promises.length) { reject(new AggregateError(errors, 'All promises were rejected')); } } ); }); if (promises.length === 0) { reject(new AggregateError(errors, 'All promises were rejected')); } }); };}最佳实践1. 总是处理 AggregateErrorasync function fetchData(sources) { try { return await Promise.any(sources.map(s => fetch(s))); } catch (error) { if (error instanceof AggregateError) { console.error('所有数据源都失败了'); throw new Error('无法获取数据'); } throw error; }}2. 提供降级方案async function fetchWithFallback(sources, fallbackData) { try { const response = await Promise.any(sources.map(s => fetch(s))); return await response.json(); } catch (error) { if (error instanceof AggregateError) { console.warn('所有数据源都失败,使用降级数据'); return fallbackData; } throw error; }}3. 记录失败原因async function fetchWithLogging(sources) { try { return await Promise.any(sources.map(s => fetch(s))); } catch (error) { if (error instanceof AggregateError) { error.errors.forEach((err, index) => { console.error(`${sources[index]} 失败:`, err.message); }); throw new Error('无法获取数据'); } throw error; }}总结返回第一个成功的 Promise:只要有一个成功就立即返回AggregateError 处理所有失败:所有 Promise 都失败时返回 AggregateError适合多数据源场景:从多个数据源获取数据,使用最快成功的与 Promise.race() 不同:只返回成功的结果,不返回失败的结果与 Promise.all() 不同:不需要全部成功,只要一个成功即可提供降级方案:所有失败时可以提供降级数据记录失败原因:AggregateError 包含所有失败的原因