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

Node.js中for循环异步请求致Promise无法Resolve的问题

问题:Node.js Promise无法resolve,循环变量输出异常

我写了一段Node.js代码,想用for循环发起多个异步请求填充数组,然后在数组填充完成后resolve Promise,但循环里的变量i始终只输出0、1或3,Promise永远无法触发resolve。代码如下:

const InvType = ["Hat", "Face", "FaceAccessory", "HairAccessory", "BackAccessory", "NeckAccessory", "FrontAccessory", "WaistAccessory", "Gear"]

var Prom = new Promise((resolve, reject) => {
        var Inv = []

        for (let i = 0; i < InvType.length; i++) {
            https.get('https://inventory.roblox.com/v1/users/111138402/assets/collectibles?assetType=' + InvType[i] + '&sortOrder=Asc&limit=100', (resp) => {
                let data = '';

                resp.on('data', (chunk) => {
                    data += chunk;
                });

                resp.on('end', () => {
                    var arrayLength = JSON.parse(data).data.length;
                    for (var v = 0; v < arrayLength; v++) {
                        Inv.concat(JSON.parse(data).data[v])
                        console.log(i)
                    }
                    if (i >= 9) {
                        resolve(Inv)
                    }
                });

            }).on("error", (err) => {
                console.log("Error: " + err.message);
            });
        }
    })

我希望所有数据都获取完成后再resolve,避免后续代码提前执行,求帮忙排查问题。


问题分析与解决方案

核心问题点

  1. 判断条件错误:InvType的长度是9,数组索引从0到8,所以i的最大值是8,i >=9的条件永远不会成立,这是Promise无法resolve的直接原因。
  2. 异步请求的并发无序性:https.get是异步操作,循环会一次性发起所有请求,但回调函数的执行顺序不固定(取决于接口响应速度),所以你看到的i输出0、1、3是因为这些请求先返回了,其他请求还处于pending状态。
  3. 数组拼接错误:Inv.concat(...)不会修改原数组Inv,而是返回一个新数组,所以你的Inv始终是空数组,数据根本没被存进去。
  4. 未跟踪所有请求完成状态:当前逻辑只在单个请求回调里判断是否resolve,但无法保证所有请求都已完成。

修复方案

把每个异步请求包装成独立的Promise,用Promise.all等待所有请求完成后再统一处理数据并resolve,这样能确保所有数据都获取完毕后才执行后续逻辑。

修改后的代码:

const https = require('https');
const InvType = ["Hat", "Face", "FaceAccessory", "HairAccessory", "BackAccessory", "NeckAccessory", "FrontAccessory", "WaistAccessory", "Gear"];

// 把单个请求包装成Promise
function fetchInventory(type) {
    return new Promise((resolve, reject) => {
        const url = `https://inventory.roblox.com/v1/users/111138402/assets/collectibles?assetType=${type}&sortOrder=Asc&limit=100`;
        https.get(url, (resp) => {
            let data = '';
            resp.on('data', (chunk) => data += chunk);
            resp.on('end', () => {
                try {
                    const result = JSON.parse(data);
                    resolve(result.data || []); // 直接返回数据数组,后续统一合并
                } catch (err) {
                    reject(err);
                }
            });
        }).on("error", reject);
    });
}

// 用Promise.all等待所有请求完成
const Prom = Promise.all(InvType.map(type => fetchInventory(type)))
    .then(allData => {
        // 合并所有请求返回的数组
        const Inv = allData.flat(); // flat可以把二维数组转成一维
        return Inv;
    })
    .catch(err => {
        console.error('请求出错:', err.message);
        throw err; // 抛出错误让后续处理
    });

// 后续使用示例
Prom.then(inventory => {
    console.log('完整 inventory:', inventory);
}).catch(err => {
    console.error('处理失败:', err);
});

关键改进点

  • 每个请求独立封装成Promise,逻辑更清晰,也方便错误处理
  • 用Promise.all自动等待所有请求完成,无需手动计数
  • 用flat()合并所有返回的数组,替代原有的循环拼接,更简洁
  • 修复了数组拼接的问题,确保数据能正确存入
  • 统一处理解析JSON的异常,避免单个请求出错导致整个流程卡住

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:40:27