别再死记硬背了!用这5个真实场景,彻底搞懂Promise.all、race、any怎么选
5个真实场景解析Promise.all、race、any的核心差异与选型指南商品详情页的加载进度条突然卡在80%后台同时发起的三个API请求中有一个查询物流信息的接口响应缓慢整个页面陷入等待。这正是去年我们团队优化电商平台时遇到的实际问题——当多个异步操作并行时如何智能控制流程本文将用五个真实开发场景带你掌握Promise高阶方法的选型逻辑。1. 并发控制基础重新理解Promise三剑客在商品详情页的典型加载流程中通常需要并行获取商品基本信息、库存状态和用户评价数据。假设我们用三个独立的Promise来表示这些异步请求const productInfo fetch(/api/product/123); const stockStatus fetch(/api/inventory/123); const userReviews fetch(/api/reviews/123);Promise.all的工作机制就像严格的团队领导必须所有成员都成功报告resolve才会汇总结果任一成员失败reject立即终止整个流程结果数组顺序与输入Promise顺序严格对应// 商品页完整数据加载 Promise.all([productInfo, stockStatus, userReviews]) .then(([info, stock, reviews]) { renderProductPage(info, stock, reviews); }) .catch(err { showErrorToast(部分数据加载失败); });Promise.race的行为像体育比赛的终点摄像机只捕捉第一个冲过终点线的选手无论成功失败其他选手仍在继续比赛但结果被忽略典型场景请求超时控制// 请求超时处理 const timeout new Promise((_, reject) { setTimeout(() reject(new Error(请求超时)), 5000); }); Promise.race([productInfo, timeout]) .then(info { renderBasicProductInfo(info); }) .catch(() { showNetworkWarning(); });Promise.any则像乐观的投资者只要有一个成功案例就视为整体成功全部失败时才认为投资失败浏览器兼容性提示需要Chrome 85或Polyfill方法成功条件失败条件结果特征Promise.all全部成功任一失败数组按输入顺序排列Promise.race第一个完成第一个完成且为拒绝单个最快结果Promise.any任一成功全部失败单个最先成功结果2. 全有或全无Promise.all的严谨之道在订单结算页面的场景中我们需要同时验证库存、优惠券和配送地址三项信息任何一项不满足条件都应终止结算流程。这正是Promise.all的完美应用场景async function validateCheckout() { try { const [isStockValid, isCouponValid, isAddressValid] await Promise.all([ checkInventory(order.items), verifyCoupon(order.couponCode), validateAddress(order.shippingAddress) ]); if (isStockValid isCouponValid isAddressValid) { proceedToPayment(); } } catch (error) { showCheckoutError(error.message); } }错误处理的高级技巧配合async/await使用try-catch结构更清晰在catch块中可通过error对象分析具体失败原因重要提示即使有Promise被reject其他Promise仍会继续执行实际项目中建议为每个Promise添加独立的catch处理避免全局catch后丢失错误详情批量文件上传是另一个典型用例。当需要确保所有文件都成功上传后才能提交表单时const uploadTasks selectedFiles.map(file uploadFile(file).catch(err { // 为每个上传任务单独处理错误 console.error(文件${file.name}上传失败, err); throw err; // 重新抛出以触发Promise.all的catch }) ); Promise.all(uploadTasks) .then(() { submitForm(); }) .catch(() { alert(部分文件上传失败请检查后重试); });3. 竞速场景Promise.race的极速哲学在电商平台的CDN资源加载优化中我们同时从多个镜像源请求同一资源采用最先响应的结果const cdnSources [ https://cdn1.example.com/static/main.js, https://cdn2.example.com/static/main.js, https://cdn3.example.com/static/main.js ]; const resourceRequests cdnSources.map(url fetch(url).then(res { // 取消其他未完成的请求 resourceRequests.forEach(req req.abort?.()); return res.blob(); }) ); Promise.race(resourceRequests) .then(script { loadScript(script); }) .catch(() { fallbackToLocalScript(); });竞速模式的高级应用超时控制包装原始Promise与定时reject的Promise降级策略优先尝试现代API超时后回退传统方案性能监控记录各源的响应时间差异// 带超时的API请求 function fetchWithTimeout(url, timeout 3000) { const timeoutReject new Promise((_, reject) { setTimeout(() reject(new Error(请求超时)), timeout); }); return Promise.race([ fetch(url), timeoutReject ]); }一个常见的误区是认为Promise.race会取消其他Promise的执行。实际上未被采用的Promise仍会继续执行直到完成只是它们的结果被忽略了。在需要真正取消操作的场景需要配合AbortController等机制。4. 宽容策略Promise.any的弹性思维当我们的应用需要从多个备用数据源获取信息时Promise.any提供了完美的解决方案。例如在天气预报应用中const weatherSources [ fetch(https://api.weather.com/v1), fetch(https://backup.weather-api.com/v2), fetch(https://community-driven-weather.org/api) ]; Promise.any(weatherSources) .then(weatherData { updateWeatherDisplay(weatherData); }) .catch(() { showError(所有数据源均不可用); });与race的关键区别race接受第一个完成的结果无论成功失败any只接受第一个成功的结果忽略所有拒绝直到全部失败错误处理any在所有输入都拒绝时抛出AggregateError// 错误处理示例 Promise.any([ Promise.reject(错误1), Promise.reject(错误2) ]).catch(err { console.log(err.errors); // [错误1, 错误2] });在服务端渲染(SSR)场景中我们可以利用Promise.any实现多级缓存策略async function renderWithCache(page) { try { // 尝试从内存缓存、Redis缓存和数据库依次获取 const html await Promise.any([ memoryCache.get(page), redisClient.get(page:${page}), database.query(SELECT content FROM pages WHERE name ?, [page]) ]); return html; } catch { return generateFreshContent(page); } }5. 综合实战电商平台的全流程优化让我们回到最初的商品详情页案例通过组合不同的Promise策略实现分级加载async function loadProductPage(productId) { // 核心数据使用all保证完整性 const [basicInfo] await Promise.all([ fetch(/api/products/${productId}), // 其他必要数据... ]); // 次要数据使用any提升用户体验 const recommendations await Promise.any([ fetch(/api/recommendations/${productId}), getCachedRecommendations(productId), getGenericRecommendations() ]).catch(() []); // 竞品价格使用race设置超时 const competitorPrices await Promise.race([ fetchCompetitorPrices(productId), timeout(2000).then(() []) ]); return { basicInfo, recommendations, competitorPrices }; }性能优化指标对比加载策略成功条件平均耗时数据完整性纯Promise.all全部成功3200ms100%混合策略核心数据完整1800ms95%纯Promise.race第一个响应900ms65%在错误恢复方面我们实现了三级回退机制主API失败时尝试备用API备用API不可用时读取本地缓存缓存未命中返回精简数据模板async function getProductDetails(productId) { try { return await Promise.any([ fetchMainAPI(productId), fetchBackupAPI(productId), getFromCache(productId) ]); } catch { return getFallbackTemplate(); } }