
本文介绍如何在使用 `promise.all` 并行处理多个 promise 时,既确保所有请求完成后再统一处理结果,又能为每个已解析的 promise 单独执行回调函数,同时实现进度百分比监控。
Promise.all 的核心特性是“全量等待”:它不会在单个 Promise 解析时触发回调,而是等到所有 Promise 都成功解析后,才将结果数组一次性传递给 .then()。因此,若你想对每个响应单独执行逻辑(如日志记录、UI 更新或数据预处理),不能在 fetchData(url).then(...) 中直接调用回调(那会立即执行且与 Promise.all 无关),而应分两步处理:
- 进度监控:在构造 Promise 数组时,为每个原始 Promise 单独附加 .then() 监听器,用于累加完成计数并计算实时进度;
- 批量后处理:在 Promise.all(...).then(results => {...}) 中遍历最终结果数组,对每个响应执行你的业务回调(如 callbackResolve(response))。
以下是完整、可运行的实践示例:
function fetchData(url) {
return fetch(url)
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
return response.json(); // 或根据需要返回 text() / blob() 等
});
}
const urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
];
const promises = urls.map(fetchData);
// ✅ 步骤1:独立监听每个 Promise 的完成(用于进度)
let resolvedCount = 0;
const total = promises.length;
promises.forEach((promise, index) => {
promise.then(() => {
resolvedCount++;
const progress = ((resolvedCount / total) * 100).toFixed(1);
console.log(`✅ 第 ${index + 1} 个请求完成 — 进度: ${progress}%`);
}).catch(err => {
console.warn(`⚠️ 第 ${index + 1} 个请求失败:`, err.message);
});
});
// ✅ 步骤2:Promise.all 统一处理全部成功结果
Promise.all(promises)
.then(responses => {
console.log('? 所有请求已完成,开始批量处理...');
responses.forEach((response, i) => {
// ? 在此处执行你的每个响应专属逻辑
callbackResolve(response, urls[i], i); // 示例:传入响应、URL 和索引
});
})
.catch(error => {
console.error('❌ Promise.all 失败(任一 Promise 被 reject):', error);
});
// 示例回调函数(请按需替换为你自己的逻辑)
function callbackResolve(data, url, index) {
console.log(`→ 处理第 ${index + 1} 个响应:`, { url, id: data.id, title: data.title?.substring(0, 40) + '...' });
}关键注意事项:
- Promise.all 是“全或无”机制:只要有一个 Promise reject,整个 Promise.all 就立即 reject,后续 .then() 不会执行。如需容错(即部分失败仍继续),请改用 Promise.allSettled;
- 进度统计仅反映“已 resolve 的数量”,不区分 success/fail;若需精确的成功率,应在 .then() 和 .catch() 中分别维护两个计数器;
- 避免在 fetchData 内部直接调用 callbackResolve — 这会破坏 Promise.all 的同步协调能力,导致回调时机不可控;
- 实际项目中,建议将进度状态通过 useState(React)或事件总线(Vue/全局)暴露给 UI 层,而非仅依赖 console.log。
通过这种分离设计,你既能享受 Promise.all 的高效并发优势,又能灵活控制每个响应的生命周期行为,并获得清晰的执行进度反馈。










