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

Node.js中for循环调用API时id_Arr[i]无效问题排查

问题描述

尝试用for循环遍历字符串数组,将数组元素id_Arr[i]作为API链接的一部分发起请求。该逻辑在常规JS/Angular中正常运行,但在Node.js环境下,请求虽能发送,但id_Arr[i]未被识别为数组元素引用,拼出的URL导致返回结果提示端点不存在;若移除for循环,直接在API路径中写入具体ID则可正常运行。

具体流程:先调用API获取所有赛事信息,筛选出正在进行的赛事,将其ID存入id_Arr数组;随后通过for循环遍历id_Arr,使用数组中的ID拼接API链接发起GET请求。

代码如下:

const https = require('node:https');

arr = new Array();
id_Arr = new Array();
race_arr = new Array();


// Get Schedule

var start = new Date();

https.get('link to api', (res) => {
    console.log('statusCode:', res.statusCode);
    console.log('headers:', res.headers);

    res.setEncoding('utf8');
    let rawData = '';
    res.on('data', (chunk) => { rawData += chunk; });
    res.on('end', () => {
        try {
            const jsoData = JSON.parse(rawData);
            arr.push(jsoData.sport_events);
            // console.log(arr);
            var xm = arr[0].filter(function (item) {
                return item.status == 'live';
            });

            for (i = 0; i <= xm.length - 1; i++) {
                id_Arr.push(xm[i].id);
            }
        } catch (e) {
            console.error(e.message);
        }
    });
}).on('error', (e) => {
    console.error(e);
});

// Get Live Circuit

for (i = 0; i <= id_Arr.length - 1; i++) {
    https.get('https://link-toapi/' + id_Arr[i] + '/api-key-rest-of-link', (res) => {
        console.log('statusCode:', res.statusCode);
        console.log('headers:', res.headers);

        res.setEncoding('utf8');
        let rawData = '';
        res.on('data', (chunk) => { rawData += chunk; });
        res.on('end', () => {
            try {
                const parsedDat = JSON.parse(rawData);
                race_arr.push(parsedDat);
                console.log(race_arr);
            } catch (e) {
                console.error(e.message);
            }
        });
    }).on('error', (e) => {
        console.error(e);
    });

}

var time = new Date() - start;

console.log(time)
问题原因

核心问题是Node.js网络请求的异步特性+全局变量污染:

  1. https.get是异步操作,发起第一个获取赛事列表的请求后,代码不会等待请求完成,直接执行后面的Get Live Circuit循环。此时第一个请求的end回调还没触发,id_Arr是空数组,id_Arr[i]实际是undefined,拼接到URL后变成https://link-toapi/undefined/api-key-rest-of-link,自然会提示端点不存在。
  2. 你使用了全局变量(i、arr等未用let/const限制作用域),后续循环的i会被第一个回调里的循环覆盖,进一步加剧时序混乱。
解决方案

方案1:将后续请求放到第一个请求的回调内部

确保只有在获取到赛事ID并填充到数组后,才发起后续请求:

const https = require('node:https');

let arr = [];
let id_Arr = [];
let race_arr = [];

var start = new Date();

// Get Schedule
https.get('link to api', (res) => {
    console.log('statusCode:', res.statusCode);
    console.log('headers:', res.headers);

    res.setEncoding('utf8');
    let rawData = '';
    res.on('data', (chunk) => { rawData += chunk; });
    res.on('end', () => {
        try {
            const jsoData = JSON.parse(rawData);
            arr.push(jsoData.sport_events);
            const xm = arr[0].filter(item => item.status === 'live');

            // 拿到ID后立即发起请求
            for (let i = 0; i < xm.length; i++) {
                const eventId = xm[i].id;
                https.get(`https://link-toapi/${eventId}/api-key-rest-of-link`, (res) => {
                    console.log('statusCode:', res.statusCode);
                    console.log('headers:', res.headers);

                    res.setEncoding('utf8');
                    let rawData = '';
                    res.on('data', (chunk) => { rawData += chunk; });
                    res.on('end', () => {
                        try {
                            const parsedDat = JSON.parse(rawData);
                            race_arr.push(parsedDat);
                            console.log(race_arr);
                        } catch (e) {
                            console.error(e.message);
                        }
                    });
                }).on('error', (e) => {
                    console.error(e);
                });
            }
        } catch (e) {
            console.error(e.message);
        }
    });
}).on('error', (e) => {
    console.error(e);
});

var time = new Date() - start;
console.log(time)

方案2:用Promise封装请求+async/await(更清晰的异步控制)

将https.get封装成Promise,用async/await控制执行顺序,代码更易维护:

const https = require('node:https');

// 封装https.get为Promise
function getRequest(url) {
    return new Promise((resolve, reject) => {
        https.get(url, (res) => {
            res.setEncoding('utf8');
            let rawData = '';
            res.on('data', (chunk) => { rawData += chunk; });
            res.on('end', () => {
                try {
                    resolve(JSON.parse(rawData));
                } catch (e) {
                    reject(e);
                }
            });
        }).on('error', reject);
    });
}

// 主逻辑用async函数
async function fetchLiveRaces() {
    let start = new Date();
    try {
        // 1. 获取赛事列表
        const scheduleData = await getRequest('link to api');
        const liveEvents = scheduleData.sport_events.filter(item => item.status === 'live');
        
        // 2. 并行发起所有赛事详情请求
        const racePromises = liveEvents.map(event => 
            getRequest(`https://link-toapi/${event.id}/api-key-rest-of-link`)
        );
        const race_arr = await Promise.all(racePromises);
        
        console.log(race_arr);
        console.log(new Date() - start);
    } catch (e) {
        console.error(e.message);
    }
}

// 执行主函数
fetchLiveRaces();

额外优化点

  • 用let/const声明变量,避免全局变量污染;
  • 用模板字符串(`xxx${var}xxx`)替代字符串拼接,更简洁;
  • 用Array.map和Promise.all并行发起请求,提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:20:24