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

Node.js循环API请求异步问题:币种与文件无法正确关联

Node.js异步循环问题解决:绑定币种变量并正确保存FRR值

问题描述

习惯使用PHP,首次开发Node.js程序时遇到以下同步/异步问题:

  • 针对币种数组TESTUSDT,TESTUSD,TESTBTC通过for循环发起API请求,返回的JSON结果顺序随机
  • 保存值到文件时仅最后一个币种生效
  • console.log中变量c始终显示TESTBTC
  • 需要将各币种对应的FRR值正确保存到对应文件

原代码:

const axios = require('axios');
const fs = require('fs');

var currencies = (fs.readFileSync('funding_currencies.txt', 'utf-8'));
const currencies_array = currencies.split(",");

for (i = 0; i < currencies_array.length - 1; i++) {
  var c = currencies_array[i];

  if (fs.existsSync('frr_' + c + '.txt')) {
    var oldfrr = (fs.readFileSync('frr_' + c + '.txt', 'utf-8'));
    fs.writeFile("frr_" + c + "_old.txt", oldfrr, function (err) {
      if (err) {
        return console.log(err);
      }
    });
  }

  console.log("funding/stats/" + c + "/hist");

  var baseUrl = "https://api-pub.bitfinex.com/v2/";
  var pathParams = "funding/stats/f" + c + "/hist";
  var queryParams = "limit=1";

  axios.get(`${baseUrl}/${pathParams}?${queryParams}`)
  .then(response => {
    console.log(response.data);
    var raw = JSON.stringify(response.data);
    var partsArray = raw.split(',');
    var frr = 100 * 365 * partsArray[3];
    console.log(c + ' - Daily Rate % FRR: ' + frr);

    fs.writeFile("frr_" + c + ".txt", frr, function (err) {
      if (err) {
        return console.log(err);
      }
      console.log("FRR for " + c + " saved to file");
    });
  }, error => {
    console.log(error);
  })

}

原输出:

funding/stats/TESTUSDT/hist
funding/stats/TESTUSD/hist
funding/stats/TESTBTC/hist
[
  [
    1675598700000,   null,
    null,            0.00000128,
    39.56,           null,
    null,            748236.20624443,
    676828.07200483, null,
    null,            10865216.1584813
  ]
]
TESTBTC - Daily Rate % FRR: 0.04672
[
  [
    1675598700000,   null,
    null,            0.00002035,
    69.88,           null,
    null,            519081.88192342,
    519081.08203316, null,
    null,            0
  ]
]
TESTBTC - Daily Rate % FRR: 0.742775
[
  [
    1675598700000,    null,
    null,             0.00000386,
    28.31,            null,
    null,             6372417.33205204,
    6372417.33205204, null,
    null,             0
  ]
]
TESTBTC - Daily Rate % FRR: 0.14089000000000002
FRR for TESTBTC saved to file
FRR for TESTBTC saved to file
FRR for TESTBTC saved to file

问题原因

  1. var变量作用域缺陷:var c是函数级作用域,for循环中每次迭代都会覆盖同一个变量,异步回调触发时循环已结束,c的值固定为最后一个币种TESTBTC。
  2. 异步操作无序性:axios.get和fs.writeFile均为异步操作,执行顺序不固定,导致结果返回和文件保存顺序随机。

解决方案

方案1:用let绑定块级作用域变量+async/await控制异步流程

const axios = require('axios');
const fs = require('fs').promises;
const fsSync = require('fs');

async function processCurrencies() {
  const currencies = fsSync.readFileSync('funding_currencies.txt', 'utf-8');
  const currencies_array = currencies.split(",");

  for (let i = 0; i < currencies_array.length - 1; i++) {
    const c = currencies_array[i];
    console.log("funding/stats/" + c + "/hist");

    // 备份旧FRR文件
    try {
      if (fsSync.existsSync(`frr_${c}.txt`)) {
        const oldfrr = fsSync.readFileSync(`frr_${c}.txt`, 'utf-8');
        await fs.writeFile(`frr_${c}_old.txt`, oldfrr);
      }
    } catch (err) {
      console.error(err);
    }

    // 请求API并处理FRR值
    try {
      const baseUrl = "https://api-pub.bitfinex.com/v2/";
      const pathParams = `funding/stats/f${c}/hist`;
      const queryParams = "limit=1";
      const response = await axios.get(`${baseUrl}/${pathParams}?${queryParams}`);
      
      // 直接从响应数组中取值,替代JSON拆分的低效方式
      const frrValue = response.data[0][3];
      const frr = 100 * 365 * frrValue;
      console.log(`${c} - Daily Rate % FRR: ${frr}`);
      
      await fs.writeFile(`frr_${c}.txt`, frr.toString());
      console.log(`FRR for ${c} saved to file`);
    } catch (error) {
      console.error(`处理币种${c}时出错:`, error);
    }
  }
}

processCurrencies();

方案2:用forEach遍历数组+Promise.all并行处理

const axios = require('axios');
const fs = require('fs').promises;
const fsSync = require('fs');

async function processCurrencies() {
  const currencies = fsSync.readFileSync('funding_currencies.txt', 'utf-8');
  const currencies_array = currencies.split(",");

  // 并行处理所有币种,forEach迭代自带独立作用域
  await Promise.all(currencies_array.slice(0, -1).map(async (c) => {
    console.log("funding/stats/" + c + "/hist");

    try {
      if (fsSync.existsSync(`frr_${c}.txt`)) {
        const oldfrr = fsSync.readFileSync(`frr_${c}.txt`, 'utf-8');
        await fs.writeFile(`frr_${c}_old.txt`, oldfrr);
      }
    } catch (err) {
      console.error(err);
    }

    try {
      const baseUrl = "https://api-pub.bitfinex.com/v2/";
      const pathParams = `funding/stats/f${c}/hist`;
      const queryParams = "limit=1";
      const response = await axios.get(`${baseUrl}/${pathParams}?${queryParams}`);
      
      const frrValue = response.data[0][3];
      const frr = 100 * 365 * frrValue;
      console.log(`${c} - Daily Rate % FRR: ${frr}`);
      
      await fs.writeFile(`frr_${c}.txt`, frr.toString());
      console.log(`FRR for ${c} saved to file`);
    } catch (error) {
      console.error(`处理币种${c}时出错:`, error);
    }
  }));
}

processCurrencies();

关键改进点

  • 用let或forEach的独立作用域解决变量绑定问题,确保异步回调能捕获当前迭代的币种值
  • 使用async/await配合fs.promises.writeFile,让异步操作顺序可控,避免回调嵌套
  • 直接从响应数组中提取FRR值,替代JSON序列化再拆分的低效做法
  • 增加错误捕获逻辑,避免单个币种处理失败导致整个流程中断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:16:06