forEach循环多次返回数据:如何获取最终完整数组?
问题:Node.js异步读取文件后仅输出最终完整数组
我编写了一段Node.js代码,逻辑如下:
- 先读取上级目录的
test.json文件,提取其中的token字段存入数组arr; - 遍历
arr,根据每个token读取对应目录(如../testing/testing_info/123/info.json)下的info.json文件,解析后提取指定数据存入arr2。
目前代码每次读取完一个info.json就打印arr2,导致多次输出数组(3个文件则打印3次),虽然最终能得到目标数组,但我希望仅获取并访问最终的完整arr2。尝试通过判断arr2.length == arr.length来打印,却未生效,请求解决。
当前输出
[ '1', '0' ] [ '1', '0', '2', '0' ] [ '1', '0', '2', '0', '3', '-14.05' ]
期望输出
[ '1', '0', '2', '0', '3', '-14.05' ]
原代码
fs.readFile('../testing/test.json', 'utf8', function(err, data) { let arr = []; var json_parse = JSON.parse(data) for (var i = 0; i < json_parse.length; i++) { arr.push(json_parse[i].token) } var arr2 = [] arr.forEach((function(item) { var results_max = [] fs.readFile('../testing/testing_info/' + item + "/info.json", 'utf8', function(err, data) { var parse = JSON.parse(data) var response_string = JSON.stringify(data) var response_clean = response_string.replace(/["\"[\\%"\\\}"""]+/g, '') var response_split = response_clean.split(',') var contract_address = response_split[1].split(':')[1] var percent_change = response_split[6].split(':')[1] arr2.push(contract_address, percent_change) results_max.push(percent_change) var x_max = Math.max(...results_max) console.log(arr2) }); })); });
尝试的修复代码
if (arr2.length == arr.length) { console.log(arr2) }
解决方案
问题根源
- 异步操作时序问题:
fs.readFile是异步函数,每次读取完成的回调会独立执行,你在回调里直接打印arr2,导致每次添加数据后就输出一次。 - 判断条件错误:每个
token对应往arr2里存入2个元素,所以最终arr2的长度应该是arr.length * 2,而非相等。 - 冗余的JSON处理:原代码中
JSON.parse(data)后又执行JSON.stringify(data),完全多余,直接从解析后的对象提取字段更可靠,避免字符串分割因JSON格式变化(如空格、键顺序改变)出错。
修复方案1:基于回调调整判断逻辑
修改判断条件,并将检查逻辑放在每次数据添加后:
fs.readFile('../testing/test.json', 'utf8', function(err, data) { if (err) { console.error('读取test.json失败:', err); return; } let arr = []; const json_parse = JSON.parse(data); for (let i = 0; i < json_parse.length; i++) { arr.push(json_parse[i].token); } const arr2 = []; const expectedLength = arr.length * 2; // 每个token对应2个元素 arr.forEach(function(item) { fs.readFile(`../testing/testing_info/${item}/info.json`, 'utf8', function(err, data) { if (err) { console.error(`读取${item}/info.json失败:`, err); return; } // 直接使用解析后的JSON对象提取字段(推荐) const parse = JSON.parse(data); // 替换为info.json中实际对应的字段名 const contract_address = parse.contractAddress; const percent_change = parse.percentChange; // 若必须保留原字符串分割逻辑,可启用以下代码 /* const response_string = JSON.stringify(data); const response_clean = response_string.replace(/["\"[\\%"\\\}"""]+/g, ''); const response_split = response_clean.split(','); const contract_address = response_split[1].split(':')[1]; const percent_change = response_split[6].split(':')[1]; */ arr2.push(contract_address, percent_change); // 检查是否已收集完所有数据 if (arr2.length === expectedLength) { console.log(arr2); // 此处可添加后续处理逻辑 } }); }); });
修复方案2:使用Promise + async/await(推荐)
这种方式让异步代码更易读,且能确保所有操作完成后再处理最终结果:
const fs = require('fs').promises; // 使用Promise版本的fs模块 async function processData() { try { // 读取test.json并提取tokens const testData = await fs.readFile('../testing/test.json', 'utf8'); const jsonParse = JSON.parse(testData); const arr = jsonParse.map(item => item.token); const arr2 = []; // 遍历每个token,依次读取对应info.json for (const item of arr) { const infoData = await fs.readFile(`../testing/testing_info/${item}/info.json`, 'utf8'); const infoParse = JSON.parse(infoData); // 替换为info.json中实际对应的字段名 const contract_address = infoParse.contractAddress; const percent_change = infoParse.percentChange; arr2.push(contract_address, percent_change); } // 所有异步操作完成后打印最终数组 console.log(arr2); // 此处可添加后续处理逻辑 } catch (err) { console.error('处理过程出错:', err); } } processData();
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

