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

9次阅读

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

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

Promise.all 的核心特性是:只有当所有传入的 Promise 都 fulfilled(成功)时,它才返回一个包含全部结果的数组;若任一 Promise rejected(失败),则整个 Promise.all 立即 reject。因此,它本身不提供“逐个完成时触发”的机制——但我们可以巧妙组合原生 Promise 特性来同时满足「批量等待」和「单个进度/回调」两个需求。

✅ 正确方式:分离「进度监听」与「结果汇总」

关键在于:不要把回调逻辑塞进 Promise.all().then() 内部去“模拟逐个执行”,而应分别利用原始 Promise 链做进度通知,再用 Promise.all 做最终聚合

以下是一个完整、健壮的实现示例:

function fetchData(url) {   return fetch(url)     .then(res => {       if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);       return res.json(); // 或 res.text(),按需处理响应体     }); }  const urls = [   'https://jsonplaceholder.typicode.com/posts/1',   'https://jsonplaceholder.typicode.com/posts/2',   'https://jsonplaceholder.typicode.com/posts/3' ];  const promises = urls.map((url, index) =>   fetchData(url).then(data => ({     index,     url,     data,     timestamp: Date.now()   })) );  // ? Step 1:监听每个 Promise 的独立完成(用于进度) let resolvedCount = 0; const total = promises.length;  promises.forEach(promise => {   promise.then(() => {     resolvedCount++;     const progress = ((resolvedCount / total) * 100).toFixed(1);     console.log(`✅ 进度: ${progress}% (${resolvedCount}/${total})`);   }).catch(err => {     console.warn(`⚠️ 请求失败(不中断整体):`, err.message);   }); });  // ? Step 2:Promise.all 等待全部成功,统一处理结果 Promise.all(promises)   .then(results => {     console.log('? 所有请求已完成,开始批量处理结果...');     results.forEach(({ index, url, data }) => {       console.log(`[${index + 1}] ${url} →`, data.title || '(no title)');       // ✅ 在此处调用你的 callbackResolve 函数       callbackResolve({ index, url, data });     });   })   .catch(err => {     console.error('❌ Promise.all 被拒绝(至少一个请求彻底失败):', err);   });  // 示例回调函数(请按实际业务替换) function callbackResolve({ index, url, data }) {   // e.g. 更新 UI、存入缓存、触发事件等   console.log(`➡️ 已处理第 ${index + 1} 个响应:`, url); }

⚠️ 注意事项与最佳实践

  • 避免 .then(callbackResolve) 直接链在 fetchData() 上:这会导致回调在每个 Promise 解析时立即执行,与 Promise.all 的协调无关,且无法保证执行顺序或统一错误处理。
  • 进度统计需独立维护计数器:Promise.all 不暴露中间状态,必须通过遍历原始 promises 数组并为其每个元素附加 .then() 来实现。
  • 错误处理要分层
    • 单个请求失败时,.catch() 可记录警告但不应阻止其他 Promise 继续(除非业务强依赖全部成功);
    • Promise.all().catch() 则用于捕获「任一 Promise 拒绝导致整体失败」的兜底场景。
  • 如需更精细控制(如取消、超时、重试),建议封装为 Promise.race() + AbortController 或使用 p-all、p-progress 等成熟工具库。

✅ 总结

你不需要让 Promise.all “主动触发”每个回调——而是让每个 Promise 自主报告完成(更新进度),再由 Promise.all 提供最终一致的结果快照。这种职责分离的设计,既保持了代码清晰性,又兼顾了用户体验(实时进度)与工程健壮性(统一错误边界)。

text=ZqhQzanResources