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

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}`));

关键修改说明

  1. Promise封装异步逻辑:把lineReader的逐行处理包成Promise,让外部可以用await等待处理结束。
  2. async/await控制执行顺序:在for...of循环中使用await,强制循环等待当前文件处理完再进入下一个。
  3. 修正硬编码问题:原代码固定处理files[3]的逻辑被替换为遍历当前文件,避免所有循环都处理同一个文件。
  4. 消除全局变量污染:把stockLine、matDone等变量放在函数内部,避免被多个文件的处理流程互相覆盖。
  5. 优化写入逻辑:使用Promise版fs.writeFile替代回调,让代码结构更清晰。
  6. 增加文件过滤:只处理.NC后缀的文件,避免遍历到目录或无关文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:45:34