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

嵌套循环中如何用Promise.allSettled替换Async/Await

嵌套串行异步流程的Promise.allSettled并行改造方案

原实现是三层嵌套串行await,所有数据库写入操作按顺序逐个执行,IO等待时间完全累加,是耗时过长的核心原因。改造时只需要遵循「同层级无依赖操作并行,有前后依赖的操作保留执行顺序」的原则即可,不需要打破原有数据关联逻辑。

改造后可直接运行的代码

// 第一层:并行创建所有赛会(Meeting之间无任何依赖,可全并行)
const meetingTaskResults = await Promise.allSettled(
  meetingList.map(async (originMeeting) => {
    const newMeeting = await createMeeting(originMeeting);
    // 把新生成的赛会ID和该赛会下的原始赛事列表绑定,供下一层使用
    return {
      newMeetingId: newMeeting.id,
      events: originMeeting.events
    }
  })
);

// 遍历赛会创建结果,跳过失败项,逐个处理下属赛事
for (const meetingTaskRes of meetingTaskResults) {
  if (meetingTaskRes.status === 'rejected') {
    console.error('赛会创建失败:', meetingTaskRes.reason);
    continue;
  }
  const { newMeetingId, events } = meetingTaskRes.value;

  // 第二层:同个赛会下的所有赛事项目(Event)无依赖,并行创建
  const eventTaskResults = await Promise.allSettled(
    events.map(async (originEvent) => {
      const newEvent = await createEvent(originEvent, newMeetingId);
      // 把新生成的赛事ID和该赛事下的原始选手列表绑定,供下一层使用
      return {
        newEventId: newEvent.id,
        competitors: originEvent.competitors
      }
    })
  );

  // 遍历赛事创建结果,跳过失败项,逐个处理下属参赛选手
  for (const eventTaskRes of eventTaskResults) {
    if (eventTaskRes.status === 'rejected') {
      console.error('赛事项目创建失败:', eventTaskRes.reason);
      continue;
    }
    const { newEventId, competitors } = eventTaskRes.value;

    // 第三层:同个赛事下的选手处理流程无依赖,并行执行
    const competitorTaskResults = await Promise.allSettled(
      competitors.map(async (competitor) => {
        // 注意:单个选手的创建和关联写入有强依赖,必须串行执行
        const newCompetitor = await createCompetitor(competitor);
        await createRacingEventCompetitor(newCompetitor, newEventId);
        return newCompetitor;
      })
    );

    // 可选:统计选手写入失败的数量,做日志告警
    const failedCount = competitorTaskResults.filter(res => res.status === 'rejected').length;
    if (failedCount > 0) {
      console.error(`当前赛事项目共有${failedCount}名选手信息写入失败`);
    }
  }
}

关键逻辑说明

  • 层级依赖完全保留:Event必须等所属Meeting创建完成拿到meeting.id后才开始创建,选手和赛事的关联关系必须等选手、Event都创建完成拿到对应ID后才写入,不会出现外键缺失、关联错误的问题
  • 同层级无依赖操作全并行:所有Meeting之间、同一个Meeting下的所有Event之间、同一个Event下的不同选手处理流程之间都没有依赖,全部丢入Promise.allSettled并行执行,最大化压缩IO等待时间
  • 容错性更高:Promise.allSettled不会因为单个任务失败中断整个流程,你可以在每一层结果遍历的位置加失败日志、重试、告警逻辑,不会出现原来串行场景下一个数据写入失败,后续所有数据全部卡断的问题

大数量场景的优化注意点

  • 必须加并发控制:你提到单次最多要写入1万行数据,如果一次性把所有任务全部推入执行队列,瞬间产生的大量数据库请求会打满连接池,甚至触发数据库写入限流。建议根据数据库的承载能力设置并发上限(比如同时最多执行30~50个写入任务),实现简单的任务排队分批执行即可。
  • 不要强行拆分有依赖的步骤:比如单个选手的createCompetitor和createRacingEventCompetitor是强依赖关系,必须等选手创建完成拿到选手ID才能写入关联关系,这两个步骤不能拆成并行任务,否则会写入无效的关联数据。
  • 性能提升参考:按你给出的最大数据量测算,原串行逻辑总共有超过2万次IO操作,改造后总耗时会从原来的5分钟压缩到几十秒级别,提升效果非常明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:36:24