// 假设有三个异步请求:获取用户信息、获取商品列表、获取消息通知 const fetchUserInfo = fetch('/api/user'); const fetchProducts = fetch('/api/products'); const fetchNotifications = fetch('/api/notifications'); Promise.all([fetchUserInfo, fetchProducts, fetchNotifications]) .then(([userInfo, products, notifications]) => { // 只有当三个请求都成功时,才会进入这里 renderUserPage(userInfo, products, notifications); }) .catch(error => { // 如果任何一个请求失败,就会跳到这里 console.error('有一个请求失败了:', error); showErrorPage('页面加载失败,请重试!'); });场景分析: 如果 fetchNotifications(获取通知)的接口挂了,返回了 500 错误,那么即使 fetchUserInfo 和 fetchProducts 已经成功请求回来了数据,Promise.all 也会立刻终止,直接跳入 .catch 分支。
// 成功状态 { status: 'fulfilled', value: /* 成功的结果 */ } // 失败状态 { status: 'rejected', reason: /* 失败的原因(错误对象)*/ }三、如何使用 Promise.allSettled?
Promise.allSettled([fetchUserInfo, fetchProducts, fetchNotifications]) .then((results) => { // 注意:这里永远不会 catch // results 是一个包含三个对象的数组 const userInfo = results[0].status === 'fulfilled' ? results[0].value : null; const products = results[1].status === 'fulfilled' ? results[1].value : null; const notifications = results[2].status === 'fulfilled' ? results[2].value : null; // 我们可以针对每个结果进行精细化处理 if (userInfo && products) { // 只要核心数据(用户和商品)还在,就渲染页面 renderUserPage(userInfo, products, notifications); // notifications 可能是 null if (!notifications) { showToast('通知获取失败,不影响主要功能'); } } else { // 如果核心数据缺失,再显示错误页 showErrorPage('核心数据加载失败'); } }); // 不需要 .catch,因为它永远不会被触发重构后的优势:
信息完整:我们可以确切地知道每个任务的执行结果,并据此做出更细致的 UI 响应。
特性 | Promise.all | Promise.allSettled |
---|---|---|
核心原则 | 全部或无一(All-or-nothing) | 有始有终(Complete-all) |
最终状态 | 如果有一个失败,则变为 Rejected | 永远变为 Fulfilled |
结果 | 所有成功的结果的数组 | 描述每个 Promise 结果的对象数组 |
适用场景 | 任务强依赖:多个任务必须全部成功才能进行下一步(例如:下单需要同时校验库存、优惠券、地址都有效) | 任务弱依赖:需要知道每个任务的最终状态,即使某些失败也不影响整体(例如:批量操作、页面初始化加载多个独立模块、上报日志) |