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

如何基于fetch响应异步处理动态数组实现并发请求处理

实现方案

原串行逻辑慢的核心原因是每次只发一个请求,大量时间浪费在等IO返回,完全可以做并发处理,下面给两个可直接用的实现,都满足「所有节点完整处理、不要求顺序」的需求。


版本1:无并发上限最简实现

逻辑最直白,按批次把当前待处理的所有节点一次性并发请求,等整批返回后再处理下一批发现的新节点,加了去重逻辑避免重复请求同一个节点。

// 记录已经请求过的节点,避免重复发请求
const visited = new Set();
// 待处理节点队列
let pendingNodes = [ancestor];
visited.add(ancestor);

while (pendingNodes.length > 0) {
  // 一次性并发发起当前所有待处理节点的请求
  const relativesResult = await Promise.all(
    pendingNodes.map(node => fetchRelatives(node))
  );

  // 收集这一批返回的、没处理过的祖先节点,作为下一批的待处理队列
  const nextBatch = [];
  for (const relative of relativesResult) {
    for (const ancestorItem of relative.ancestors) {
      if (!visited.has(ancestorItem)) {
        visited.add(ancestorItem);
        nextBatch.push(ancestorItem);
      }
    }
  }

  pendingNodes = nextBatch;
}

这个版本适合节点总量不大的场景,代码短不容易写错。如果单批节点量很大,一次性发几百上千个请求容易触发接口限流,建议用下面带并发控制的版本。


版本2:带并发上限的生产可用实现

支持自定义最大并发数,而且哪个请求先返回就立刻处理它的结果、塞新任务进队列,不需要等同批次其他慢请求,资源利用率更高。

// 按接口限流规则配置最大并发数,浏览器场景一般设3-10即可
const MAX_CONCURRENT = 6;
const visited = new Set();
const taskQueue = [ancestor];
visited.add(ancestor);

let runningTaskCount = 0;
let finishResolve;
// 用Promise控制全流程结束时机
const allProcessDone = new Promise(resolve => {
  finishResolve = resolve;
});

function run() {
  // 队列空了、也没有正在跑的任务,说明全量节点处理完成
  if (taskQueue.length === 0 && runningTaskCount === 0) {
    finishResolve();
    return;
  }

  // 没到并发上限就一直从队列拉任务跑
  while (runningTaskCount < MAX_CONCURRENT && taskQueue.length > 0) {
    const currentNode = taskQueue.pop();
    runningTaskCount++;

    fetchRelatives(currentNode)
      .then(res => {
        // 请求一返回就立刻处理新发现的节点,不用等其他请求
        for (const ancestorItem of res.ancestors) {
          if (!visited.has(ancestorItem)) {
            visited.add(ancestorItem);
            taskQueue.push(ancestorItem);
          }
        }
      })
      .finally(() => {
        runningTaskCount--;
        // 当前任务结束,立刻拉新任务补位
        run();
      });
  }
}

// 启动任务
run();
// 等待所有节点处理完成
await allProcessDone;

注意事项

  • 如果你的节点是对象类型,visited不要直接存对象引用,改成存节点的唯一标识(比如node.id),避免引用不同导致去重失效
  • 不要把并发数设得过高,否则容易触发浏览器同域名连接数限制、或者服务端限流规则
  • 两个版本的最终处理结果和原串行逻辑完全一致,只是请求并发度更高,执行速度会快数倍到数十倍不等,取决于树的深度和单请求耗时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:24:31