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

Node.js使用fetch循环发请求时请求在for循环执行完毕后才触发问题咨询

问题原因

你看到的循环执行完成后才打印响应结果,是Node.js事件循环的固有执行逻辑,并不是请求等到循环结束才发送:

  • 所有同步代码(for循环、console.log(i)、checkbalance的同步执行部分)会优先在主线程执行完毕
  • fetchUrl属于异步IO操作,它的回调函数会被加入任务队列,必须等主线程的同步代码全部执行完成后,才会被事件调度器取出执行
  • 实际上请求在循环调用checkbalance的时候就已经发送出去了,只是响应回来后的回调被暂时挂起,等待同步代码跑完才执行
解决方案

基础版本(满足核心需求)

你当前的代码其实已经满足「循环内同步处理其他任务、无需等待请求返回、响应到达后异步处理」的需求,只需要修复var变量声明导致的作用域问题即可:

const fetchUrl = require("fetch").fetchUrl;
// 把var改为let,使用块级作用域避免循环变量共享的问题
for (let i = 0; i < 10; i++) {
  console.log(i);
  // 此处可插入你需要同步处理的其他任务,不会等待请求返回
  checkbalance(i);
}

function checkbalance(req) {
  const urlCheckBalance =
    "https://api.etherscan.io/api?module=account&action=balancemulti&address=" +
    req +
    "&tag=latest&apikey=<api key>";

  fetchUrl(urlCheckBalance, function (error, meta, body) {
    // 响应返回后自动异步执行该回调,不会阻塞主线程任务
    console.log(body.toString());
  });
}

边循环边处理响应版本

如果你的循环内同步任务耗时较长,希望循环执行过程中就能处理已经返回的响应,可以通过setImmediate给事件循环留出回调处理时间:

const fetchUrl = require("fetch").fetchUrl;

(async function runLoop() {
  for (let i = 0; i < 10; i++) {
    // 让出主线程,让已返回的请求回调可以执行
    await new Promise(resolve => setImmediate(resolve));
    console.log(i);
    // 同步处理其他任务
    checkbalance(i);
  }
})()

function checkbalance(req) {
  const urlCheckBalance =
    "https://api.etherscan.io/api?module=account&action=balancemulti&address=" +
    req +
    "&tag=latest&apikey=<api key>";

  fetchUrl(urlCheckBalance, function (error, meta, body) {
    console.log(`请求${req}返回结果:`, body.toString());
  });
}
额外报错说明

你返回结果里的两类报错原因:

  • 无效地址格式:etherscan的balancemulti接口需要传入合法的以太坊钱包地址,你直接传入数字i不符合接口参数要求
  • 速率限制:短时间并发请求过多,超过了etherscan免费API的请求频率限制,可以适当加请求间隔或者调整并发数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:36:02