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

Node.js异步循环中trainNo输出空对象的问题求助

问题分析与解决方案

问题根源:不是作用域,是异步执行时机问题

你遇到的情况和作用域无关,核心原因是**forEach不支持等待异步回调执行完毕**:

  • 你传给forEach的是async函数,forEach会立刻遍历完所有元素,直接执行后续的console.log(trainNo),此时所有fetch请求还在异步处理中,trainNo还没被赋值,所以输出空对象。
  • 循环内部的console.log是在fetch请求完成、数据赋值后执行的,因此能拿到正确结果。

另外还有一个隐藏bug:你声明的routes是全局共享变量,所有循环都会修改同一个对象,最终所有火车编号对应的routes都会指向同一个引用,导致数据混乱。


修复方案

方案1:用for...of循环(逻辑清晰,顺序执行)

把forEach换成支持await的for...of,确保异步操作按顺序完成,同时每次循环创建新的routes对象:

// 顶部变量声明不变
let mainData = {};
let trainStations = {};
let trainNo = {};

// 封装成异步函数处理
async function processTrainData() {
  for (const element of data["data"]) {
    const response2 = await fetch(
      `https://india-rail.herokuapp.com/trains/getRoute?trainNo=${element["train_base"]["train_no"]}`
    );
    const data2 = await response2.json();
    
    // 每次循环创建新的routes,避免共享引用
    const routes = {};
    data2["data"].forEach((ele) => {
      routes[ele["source_stn_code"]] = true;
    });
    
    trainNo[element["train_base"]["train_no"]] = routes;
  }
  // 所有异步操作完成后再打印
  console.log(trainNo);
}

// 调用执行
processTrainData();

方案2:用Promise.all并行处理(性能更优,请求同时发起)

如果不需要按顺序处理火车数据,用Promise.all并行发起所有请求,提升效率:

let mainData = {};
let trainStations = {};
let trainNo = {};

async function processTrainData() {
  // 把每个异步任务包装成Promise
  const taskPromises = data["data"].map(async (element) => {
    const response2 = await fetch(
      `https://india-rail.herokuapp.com/trains/getRoute?trainNo=${element["train_base"]["train_no"]}`
    );
    const data2 = await response2.json();
    
    const routes = {};
    data2["data"].forEach((ele) => {
      routes[ele["source_stn_code"]] = true;
    });
    
    // 返回火车编号和对应路线数据
    return {
      trainId: element["train_base"]["train_no"],
      routes: routes
    };
  });

  // 等待所有请求完成
  const taskResults = await Promise.all(taskPromises);
  
  // 整理结果到trainNo对象
  taskResults.forEach(result => {
    trainNo[result.trainId] = result.routes;
  });

  console.log(trainNo);
}

processTrainData();

关键注意点

  1. 永远不要用forEach搭配async/await控制异步流程,forEach不会等待异步回调完成。
  2. 避免共享对象变量(比如原代码中的routes),每次循环要创建新对象,防止引用覆盖。
  3. 必须等待所有异步操作完成后,才能访问最终的trainNo数据,for...of或Promise.all是常用的两种控制方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 07:05:32