📢 欢迎来到万事技术论坛!本站仅讨论合法编程技术话题,严禁外挂/作弊/黑产/盗版内容,违者封号。

精华Promise.all 的坑:一个失败全部失败,怎么破

yuki 进阶会员

Promise.all 是快速失败语义:任何一个 reject,整个就 reject,其他请求的结果直接丢弃,哪怕它们其实已经成功了。

场景

页面要同时拉 3 个接口,希望「哪个成功先渲染哪个,失败的给个降级」。用 Promise.all 会因为一个接口挂掉导致整页空白。

解法一:Promise.allSettled(最省事)

const results = await Promise.allSettled([fetchA(), fetchB(), fetchC()]);

const ok = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value);

const failed = results
  .filter(r => r.status === 'rejected')
  .map(r => r.reason);

永不 reject,每项告诉你 status 和 value/reason。

解法二:给每个 promise 兜底(想要默认值时)

const safe = p => p.catch(err => ({ error: err, data: null }));
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()].map(safe));

还有两个兄弟别搞混

方法 语义 用途
Promise.all 全成功才成功,一个失败即失败 强依赖,缺一不可
Promise.allSettled 永不失败,返回每项状态 批量任务要统计结果
Promise.race 第一个敲定(成功或失败)的胜出 超时控制
Promise.any 第一个成功的胜出,全失败才失败 多源择优

用 race 做超时

const timeout = new Promise((_, rej) =>
  setTimeout(() => rej(new Error('timeout')), 5000));

const data = await Promise.race([fetch(url), timeout]);

注意 race 只是让 await 提前返回,那个慢请求并没有被取消。真要取消得用 AbortController:

const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000);
const res = await fetch(url, { signal: ctrl.signal });
楼主 · 2026-09-28 13:21 · 浏览 4
登录 后即可参与回复。