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

Node.js中异步操作外部打印数组返回空的问题求助

问题原因分析

你遇到的这个问题是Node.js异步非阻塞特性导致的。简单来说,你代码里的request回调和rp(options).then()都是异步任务——Node.js会把这些任务放到事件队列里,先继续执行主线程的同步代码(也就是最后那行console.log(awayPerc))。这时候异步任务还没开始执行,数组自然是空的;而在异步回调内部打印时,回调已经执行完毕,数组已经被填充,所以能看到正常数据。

解决方案:用Promise统一异步流程

为了保证在所有异步数据都获取完成后再访问数组,我们可以把回调式的request包装成Promise,然后用Promise.all或者async/await来等待所有异步操作结束,再处理数据。这样还能避免使用全局变量,让代码更清晰可控。

步骤1:把request请求包装成Promise

const rp = require('request-promise');
const cheerio = require('cheerio');
const request = require('request');

// 封装获取资金分布数据的Promise函数
const getMoneyDistribution = () => {
  return new Promise((resolve, reject) => {
    request('https://www.actionnetwork.com/mlb/live-odds', function (err, res, html) {
      if (err || res.statusCode !== 200) {
        return reject(err || new Error('Failed to fetch money distribution data'));
      }
      const $ = cheerio.load(html);
      const awayPerc = [];
      const homePerc = [];
      $('td.text-right.border-left span:first-child').each(function(i, element) {
        const awayPercs = $(this).text();
        const homePercs = $(this).next().text();
        awayPerc.push({ awayPercs });
        homePerc.push({ homePercs });
      });
      resolve({ awayPerc, homePerc });
    });
  });
};

步骤2:封装API请求为Promise函数(优化原rp代码)

// 封装获取比赛数据的Promise函数
const getGameData = () => {
  const options = { 
    url: "https://api-prod.sprtactn.co/web/v1/scoreboard/mlb?date=20180520", 
    json: true 
  };
  return rp(options).then(data => {
    const homeTeam = [];
    const awayTeam = [];
    const openOdds = [];
    const currOdds = [];
    const games = data.games;
    
    // 注意:原代码变量名重复容易混淆,这里将循环参数改为game
    games.forEach(game => {
      game.teams.forEach(team => {
        if (game.home_team_id === team.id) {
          homeTeam.push({ homeTeam: team.full_name });
        } else if (game.away_team_id === team.id) {
          awayTeam.push({ awayTeam: team.full_name });
        }
      });
      
      game.odds.forEach(odds => {
        if (odds.type === "game" && odds.book_id === "15") {
          currOdds.push({ curAway: odds.ml_away, curHome: odds.ml_home });
        } else if (odds.type === "game" && odds.book_id === "30") {
          openOdds.push({ openAway: odds.ml_away, openHome: odds.ml_home });
        }
      });
    });
    return { homeTeam, awayTeam, openOdds, currOdds };
  });
};

步骤3:用async/await等待所有异步任务完成

// 主函数:获取所有数据并处理
async function fetchAndProcessData() {
  try {
    // 并行执行两个异步请求,等待两者都完成
    const [gameData, moneyData] = await Promise.all([getGameData(), getMoneyDistribution()]);
    
    // 解构获取所有数据
    const { homeTeam, awayTeam, openOdds, currOdds } = gameData;
    const { awayPerc, homePerc } = moneyData;
    
    // 现在可以正常访问所有填充好的数据了!
    console.log('Away Team Money Distribution:', awayPerc);
    console.log('Home Teams:', homeTeam);
    console.log('Current Odds:', currOdds);
    // 这里可以添加数据合并、存储等后续逻辑
  } catch (err) {
    console.error('Error fetching data:', err);
  }
}

// 启动主函数
fetchAndProcessData();
关键注意事项
  1. 避免全局变量:全局变量在异步场景下很容易出现时序问题,把数据封装在Promise返回值里更安全。
  2. 异步任务的执行顺序:Promise.all会并行执行多个异步任务,比顺序执行效率更高;如果某个任务依赖另一个的结果,可以把await放在顺序位置。
  3. 错误处理:一定要用try/catch或者.catch()捕获异步操作中的错误,避免程序崩溃。

内容的提问来源于stack exchange,提问作者G. Boyce

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:22:19