如何在 Promise.all 完成后对每个成功响应执行回调,并实时跟踪进度

本文介绍如何在使用 `promise.all` 并行处理多个 promise 时,既确保所有请求完成后再统一处理结果,又能为每个已解析的 promise 单独执行回调函数,同时实现进度百分比监控。

Promise.all 的核心特性是“全量等待”:它不会在单个 Promise 解析时触发回调,而是等到所有 Promise 都成功解析后,才将结果数组一次性传递给 .then()。因此,若你想对每个响应单独执行逻辑(如日志记录、UI 更新或数据预处理),不能在 fetchData(url).then(...) 中直接调用回调(那会立即执行且与 Promise.all 无关),而应分两步处理:

  1. 进度监控:在构造 Promise 数组时,为每个原始 Promise 单独附加 .then() 监听器,用于累加完成计数并计算实时进度;
  2. 批量后处理:在 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}`);
      r

eturn 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 的高效并发优势,又能灵活控制每个响应的生命周期行为,并获得清晰的执行进度反馈。