Promise.all 與 Promise.allSettled:一次取數(shù)的小差別,救了我的接口
引子
同時并發(fā)調(diào)用一堆 API,既迅速又優(yōu)雅。把所有請求塞進 Promise.all,點一下部署,你會覺得自己就是 JavaScript 搖滾明星。 然而,一個細小的失敗就足以拖垮全局——我就親歷了這場事故。
這篇文章會把 Promise.all 和 Promise.allSettled 的關鍵差異講清楚,并解釋我如何因為切換到后者,躲過了一次“無聲災難”。
場景設定
我在做一個儀表盤,需要從多個微服務并發(fā)拉數(shù)據(jù):
const [user, orders, notifications] = await Promise.all([
  getUser(),
  getOrders(),
  getNotifications(),
]);一切都很順利——直到某個接口開始間歇性失敗。 當其中任意一個 Promise 拒絕時,整組調(diào)用立刻崩潰:沒有兜底、沒有部分數(shù)據(jù)、只有報錯。
輪到 Promise.allSettled 登場
與“有一個失敗就整體拒絕”的 Promise.all 不同,Promise.allSettled 會等全部 Promise 結束,并返回每一項的狀態(tài)與結果/原因。
const results = await Promise.allSettled([
  getUser(),
  getOrders(),
  getNotifications(),
]);
results.forEach(result => {
  if (result.status === 'fulfilled') {
    console.log('Success:', result.value);
  } else {
    console.warn('Failed:', result.reason);
  }
});這樣我就可以:
- 渲染部分數(shù)據(jù)(誰成功就先展示誰);
 - 標注失敗模塊(告訴用戶哪個小部件掛了);
 - 有選擇地重試(只重試失敗的那幾項)。
 
因此,應用的韌性更強,用戶體驗也更友好。盡管如此,要注意狀態(tài)分支處理更細,代碼上需要明確區(qū)分 fulfilled / rejected;與此同時,日志與監(jiān)控也要跟上,避免悄悄失敗。
要點小結
Promise.all:只要有一個失敗就立刻 reject,其余結果不再等待。Promise.allSettled:全部等待完成,返回每一項的{ status, value | reason }。- 使用建議:
 
當所有步驟必須成功(如登錄流程的多步校驗、事務性寫入)→ 用 **Promise.all**,失敗要盡快中斷。
當允許部分失敗(如儀表盤多部件、側邊小組件、可降級內(nèi)容加載)→ 用 **Promise.allSettled**,容錯更合適。
進一步的實戰(zhàn)提示
1.選擇性重試
const results = await Promise.allSettled(tasks);
const failed = results
  .map((r, i) => [r, i])
  .filter(([r]) => r.status === 'rejected')
  .map(([, i]) => tasks[i]);
if (failed.length) {
  // 退避重試或隊列重放
  await Promise.allSettled(failed.map(backoffRetry));
}2.保持響應可用即使部分失敗,也返回帶缺口的 UI(骨架屏/占位符),并附帶“刷新/重試”入口,因此用戶不會看到空白或整頁報錯。
3.區(qū)分“硬必需”與“軟可選”把關鍵數(shù)據(jù)(必須成功)與附加數(shù)據(jù)(可失?。?/span>拆分,前者走 Promise.all,后者走 Promise.allSettled,從而保證核心路徑確定性。
結語
JavaScript 給了我們強大的并發(fā)原語;在恰當時機選用恰當工具,才是高級開發(fā)者的分水嶺。 如果你的應用頻繁并行請求、或依賴并不穩(wěn)的端點,不妨試試 Promise.allSettled——也許它也會拯救你的 API。















 
 
 















 
 
 
 