JavaScript:嵌套异步函数未等待完成迭代问题求助
问题:嵌套异步逻辑导致文件处理不按顺序执行
我有两个函数,一个用fs模块读取目录文件,另一个用line-reader逐行读取文件内容。两个函数单独运行都正常,但把line-reader的逻辑嵌套到目录遍历里后,程序不会等当前文件处理完就直接跳到下一个文件。
我需要程序按以下流程执行:
- 打开文件
- 执行内部处理函数
- 当前文件处理完成后,再处理下一个文件
尝试的代码
const lineReader = require('line-reader'); var fs = require ('fs'); const { finished } = require('stream'); files = fs.readdirSync("./"); console.log(files) for( file of files ){ var doneFile="NO" stockLine = ""; stockDone = "not done" matDone = "not done" fileName = files[3].slice(0,-3); file = `${fileName}.NC` newFile = `STOCK ${fileName}.txt` console.log(newFile) lineReader.eachLine(file, function(line) { if(line.includes("(STOCK")||line.includes("(stock") ){ console.log(line); stockLine = line; console.log("INSIDE FUNCTION", stockLine); console.log(stockDone) stockDone = "DONE" console.log(stockDone) }; if(line.includes("(MAT")){ matLine = line console.log(matLine); matDone = "DONE" }; if((matDone == "DONE") & (stockDone == "DONE")){ textOut = stockLine + matLine console.log("I FOUND BOTH"); fs.writeFile(`${newFile}`, `${stockLine} ${matLine} `, function (err) { if (err) throw err; console.log('Saved!'); }); doneFile="YES" matDone = "stop" } }); };
问题原因
lineReader.eachLine是异步函数,调用后会立即返回,不会阻塞后续代码执行。而同步的for...of循环会直接进入下一次迭代,完全不会等待当前文件的逐行处理流程结束。
解决方法
把line-reader的处理逻辑封装成Promise,再用async/await让循环强制等待每个文件处理完成。同时修正原代码里的硬编码、全局变量污染等问题:
修改后的代码
const lineReader = require('line-reader'); const fs = require('fs').promises; // 使用Promise版fs,避免嵌套回调 const fsSync = require('fs'); // 保留同步读取目录的能力 // 把单文件的逐行处理封装为Promise function processSingleFile(filePath) { return new Promise((resolve) => { let stockLine = ""; let stockDone = false; let matLine = ""; let matDone = false; const fileName = filePath.slice(0, -3); const outputFile = `STOCK ${fileName}.txt`; lineReader.eachLine(filePath, (line, isLastLine) => { // 匹配STOCK行 if (line.includes("(STOCK") || line.includes("(stock")) { stockLine = line; stockDone = true; console.log(`找到STOCK行: ${line}`); } // 匹配MAT行 if (line.includes("(MAT")) { matLine = line; matDone = true; console.log(`找到MAT行: ${line}`); } // 满足终止条件:找到两行内容,或者读到文件末尾 if ((stockDone && matDone) || isLastLine) { if (stockDone && matDone) { // 写入文件 fs.writeFile(outputFile, `${stockLine} ${matLine} `) .then(() => console.log(`已写入文件: ${outputFile}`)) .catch(err => console.error(`写入失败: ${err}`)) .finally(() => resolve()); } else { console.log(`文件${filePath}未找到目标内容,跳过写入`); resolve(); } return false; // 停止继续读取后续行 } }); }); } // 主函数:用async/await实现顺序处理 async function processFilesInOrder() { const files = fsSync.readdirSync("./"); console.log(`找到文件列表: ${files}`); // 遍历文件,逐个处理,确保顺序 for (const file of files) { if (file.endsWith('.NC')) { // 只处理.NC后缀的文件 console.log(`开始处理文件: ${file}`); await processSingleFile(file); console.log(`文件${file}处理完成\n`); } } } // 启动执行 processFilesInOrder().catch(err => console.error(`全局错误: ${err}`));
关键修改说明
- Promise封装异步逻辑:把
lineReader的逐行处理包成Promise,让外部可以用await等待处理结束。 async/await控制执行顺序:在for...of循环中使用await,强制循环等待当前文件处理完再进入下一个。- 修正硬编码问题:原代码固定处理
files[3]的逻辑被替换为遍历当前文件,避免所有循环都处理同一个文件。 - 消除全局变量污染:把
stockLine、matDone等变量放在函数内部,避免被多个文件的处理流程互相覆盖。 - 优化写入逻辑:使用Promise版
fs.writeFile替代回调,让代码结构更清晰。 - 增加文件过滤:只处理
.NC后缀的文件,避免遍历到目录或无关文件。
内容的提问来源于stack exchange,提问作者CG33
相关产品推荐
相关产品推荐

