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

JavaScript中含异步操作的forEach循环结束后如何执行后续代码

问题原因

打印得到空对象{}的核心是异步执行时序错误,和score对象的作用域无关:

  • 外层数据库查询拿到赛事ID列表后,forEach遍历触发的所有内层积分查询都是异步IO操作,会被放入事件队列等待执行,不会阻塞后续同步代码运行
  • 你写的console.log(score)属于同步代码,会在所有内层查询回调执行前就直接运行,此时score还未写入任何数据,自然输出空对象
  • 你之前尝试Promise方案未生效,核心是没有将内层所有积分查询的异步操作纳入Promise等待链路,仅包装外层查询无法感知内层异步任务的执行状态
  • 原代码还存在逻辑bug:积分累加的判断条件写为score[element["points"]] != undefined,判断对象错误,就算时序正确也无法正常完成积分累加
修复实现

不要用普通forEach处理需要等待异步回调的遍历逻辑,将每个数据库查询包装为Promise,通过Promise.all等待所有异步查询、积分累加操作全部完成后,再执行后续逻辑,修复后代码如下:

async driversBySeason(season) {
  const score = {};
  // 查询指定赛季所有赛事ID
  const raceIdQuery = `SELECT raceId FROM races WHERE year = ?`;
  const [raceQueryErr, raceList] = await new Promise(resolve => {
    // 用预处理传参避免SQL注入
    this.con.query(raceIdQuery, [season], (err, res) => resolve([err, res]));
  });
  if (raceQueryErr) {
    console.error(raceQueryErr);
    return score;
  }

  // 收集所有赛事的积分查询异步任务
  const pointQueryTasks = raceList.map(raceItem => {
    const pointQuery = `SELECT driverId, points FROM results WHERE raceId = ?`;
    return new Promise(resolve => {
      this.con.query(pointQuery, [raceItem.raceId], (err, resultList) => {
        if (err) {
          console.error(err);
          resolve();
          return;
        }
        // 累加当前赛事各车手积分
        resultList.forEach(resItem => {
          const driverId = resItem.driverId;
          const addPoints = Number(resItem.points) || 0;
          if (score[driverId] === undefined) {
            score[driverId] = addPoints;
          } else {
            score[driverId] += addPoints;
          }
        });
        resolve();
      });
    });
  });

  // 等待所有积分查询、累加操作全部执行完成
  await Promise.all(pointQueryTasks);

  // 此处即可拿到完整计算结果
  console.log(score);
  return score;
}
性能优化建议

循环内发起多条单数据查询的IO开销很高,完全可以通过单条联表SQL直接算出所有车手的总积分,省去Node层循环遍历累加的逻辑,性能更高代码更简洁,参考SQL如下:

SELECT driverId, SUM(points) AS totalPoints
FROM results
WHERE raceId IN (SELECT raceId FROM races WHERE year = ?)
GROUP BY driverId

使用该SQL时直接传入赛季参数,拿到的结果就是每个车手对应总积分的结构化数据,不需要额外做内存累加。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:31:17