You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保递归分页API调用在forEach循环完成后再执行后续代码

解决递归分页API调用的异步等待问题

原代码的核心问题

  1. forEach 不会等待异步操作完成,遍历过程中仅触发每个元素的异步逻辑,直接进入后续代码块。
  2. 手动嵌套 new Promise 属于Promise反模式,且递归时未正确返回Promise链,导致外层无法追踪递归的完成状态。
  3. 使用 JSON.parse(fieldResponse.body) 不合适,fetch 的 response.body 是ReadableStream,应使用 response.json() 异步解析JSON。

解决方案:用 Promise.all + 异步函数统一管理

方式1:用 async/await 简化递归逻辑

先封装单个元素的全量数据获取逻辑,再通过 map 收集所有异步任务,最后用 Promise.all 等待全部完成:

// 封装单个元素的分页请求逻辑
async function fetchAllForElement(element) {
  element.resultsArray = [];
  let startAt = 0;
  
  while (true) {
    // 发起分页请求
    const fieldResponse = await fetch(`/api/request?startAt=${startAt}`);
    // 异步解析JSON响应
    const results = await fieldResponse.json();
    
    // 批量添加结果到数组
    element.resultsArray.push(...results);
    
    // 判断是否是最后一页,是则终止循环
    if (results.isLast) break;
    // 否则更新分页起始位置
    startAt += 50;
  }
  
  return element;
}

// 收集所有元素的异步任务Promise
const allFetchTasks = array.map(element => fetchAllForElement(element));

// 等待所有任务完成后执行后续代码
Promise.all(allFetchTasks)
  .then(processedElements => {
    console.log('所有分页请求已完成,数据收集完毕');
    // --- 这里写你的后续代码块 ---
  })
  .catch(error => {
    console.error('请求或处理过程中出错:', error);
  });

方式2:用Promise链式调用实现递归

如果不想用async/await,也可以用纯Promise链实现递归逻辑:

function fetchAllForElement(element) {
  element.resultsArray = [];
  
  const loop = (startAt) => {
    return fetch(`/api/request?startAt=${startAt}`)
      .then(fieldResponse => fieldResponse.json())
      .then(results => {
        element.resultsArray.push(...results);
        // 最后一页返回元素,否则递归调用loop
        return results.isLast ? element : loop(startAt + 50);
      })
      .catch(error => {
        console.error('分页请求出错:', error);
        throw error; // 抛出错误,让Promise.all能捕获
      });
  };
  
  return loop(0);
}

// 同样用map+Promise.all等待所有任务完成
Promise.all(array.map(fetchAllForElement))
  .then(() => {
    // --- 后续代码块 ---
  });

关键要点

  • 用 map 替代 forEach:map 会返回每个异步任务的Promise数组,方便用 Promise.all 统一等待。
  • Promise.all:会等待数组中所有Promise都resolve后才进入then回调,确保所有分页请求完成后再执行后续代码。
  • 避免Promise嵌套:直接利用fetch返回的Promise进行链式调用或async/await,不要手动包裹多余的new Promise。
  • 错误处理:在异步逻辑中抛出错误,让Promise.all能捕获并处理,避免静默失败。

内容的提问来源于stack exchange,提问作者Quirk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 07:55:33