Promise.all 中任一 Promise 失败即中断,需用 .catch() 将每个 Promise 包装为返回 {ok, data/error} 的“永不失效”形式,再通过 Promise.all 聚合结果并分别处理成功与失败。

在 Promise.all 中,只要任意一个 Promise 被 reject,整个调用就会立即失败(抛出错误),无法获取其他已成功的结果。要实现“单个任务失败不影响整体,还能拿到成功结果 + 失败信息”,关键不是靠 Promise.all 本身,而是**提前把每个 Promise 包装成“永不失效”的形式**——即让每个子 Promise 都返回一个包含状态标记的对象(如 { ok: true, data } 或 { ok: false, error }),从而将异常从控制流中移出,转为数据态处理。
用 .catch() 把每个 Promise “兜底”成 resolved 状态
最常用、最直观的做法:对每个待并发的 Promise 显式调用 .catch(),确保它最终一定 resolve,并携带成功或失败信息:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
const tasks = [
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/config').then(r => r.json())
];
// ✅ 改造成每个都返回 { ok, data? | error? }
const safeTasks = tasks.map(p =>
p
.then(data => ({ ok: true, data }))
.catch(error => ({ ok: false, error }))
);
Promise.all(safeTasks).then(results => {
const successes = results.filter(r => r.ok);
const failures = results.filter(r => !r.ok);
console.log('成功:', successes.map(r => r.data));
console.log('失败:', failures.map(r => r.error.message));
});
封装成可复用的 safePromise 工具函数
避免重复写 .then().catch() 模板,抽成工具函数更清晰:
const safePromise = (promise) =>
promise
.then(data => ({ ok: true, data }))
.catch(error => ({ ok: false, error }));
// 使用
Promise.all([
safePromise(fetch('/api/a')),
safePromise(fetch('/api/b')),
safePromise(fetch('/api/c'))
]).then(results => {
results.forEach((result, i) => {
if (result.ok) {
console.log(`任务 ${i} 成功:`, result.data);
} else {
console.warn(`任务 ${i} 失败:`, result.error);
// ✅ 这里可做降级:用默认值、缓存、空数组等
result.data = []; // 例如接口失败时返回空数组
}
});
});
结合 async/await 写法(推荐用于复杂逻辑)
如果任务本身是 async 函数,可在内部 try/catch,保持语义清晰:
async function safeCall(fn, ...args) {
try {
const data = await fn(...args);
return { ok: true, data };
} catch (error) {
return { ok: false, error };
}
}
// 示例任务
async function fetchUser() { return (await fetch('/user')).json(); }
async function fetchPosts() { return (await fetch('/posts')).json(); }
Promise.all([
safeCall(fetchUser),
safeCall(fetchPosts),
safeCall(() => Promise.reject(new Error('模拟失败')))
]).then(results => {
results.forEach((r, i) => {
if (r.ok) {
// ✅ 正常使用 r.data
} else {
// ✅ 降级逻辑:比如显示 placeholder、加载本地 mock 数据
r.data = getFallbackDataFor(i);
}
});
});
注意点与常见误区
-
别用
Promise.allSettled替代降级逻辑:它确实能拿到所有结果(fulfilled/rejected),但 rejected 项仍会抛出错误对象,你仍需手动判断并处理;它只是“不中断”,不等于“自动降级”。真正降级动作(如替换默认值、跳过渲染、打日志)必须由你显式写。 -
网络请求失败 ≠ 业务失败:比如图片加载失败,可以 fallback 到占位图;用户信息接口失败,可用 localStorage 缓存数据兜底。降级策略要按业务定,不能只统一返回
null。 -
避免在
.catch()中吞掉关键错误:记录日志或上报监控很重要,否则问题难以发现。例如:.catch(e => { console.error('API failed:', e); return { ok: false, error: e }; })

















