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
问题原因
- var变量作用域缺陷:
var c是函数级作用域,for循环中每次迭代都会覆盖同一个变量,异步回调触发时循环已结束,c的值固定为最后一个币种TESTBTC。 - 异步操作无序性:
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
相关产品推荐
相关产品推荐

