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

Node.js中fs.readFile异步执行导致JSON加载顺序异常问题

解决Node.js中fs.readFile异步导致的执行顺序问题

问题根源在于fs.readFile是异步非阻塞API:调用它后程序会立即继续执行后续代码,不会等待文件读取完成。所以你判断file_data是否为空的逻辑先执行,此时数据还未加载,自然输出"Data not loaded.",等文件读取完成后才会执行回调里的打印逻辑。

下面是几种可行的修正方案:

方案1:使用回调函数调整执行顺序

把依赖文件数据的逻辑放到fs.readFile的回调中,确保数据加载完成后再处理:

const fs = require('fs');

class Game {
  constructor() {
    this.file_data = null;
    // 传入回调函数,等数据加载完毕再执行判断逻辑
    this.loadDefs(() => {
      if (!this.file_data) {
        console.log("Data not loaded.");
      } else {
        console.log("Data loaded successfully:", this.file_data);
        // 这里编写所有需要使用file_data的业务逻辑
      }
    });
  }

  loadDefs(callback) {
    fs.readFile('./data.json', 'utf8', (err, data) => {
      if (err) {
        console.error("读取文件失败:", err);
        callback();
        return;
      }
      this.file_data = JSON.parse(data);
      console.log(this.file_data);
      callback();
    });
  }
}

new Game();

方案2:使用Promise + async/await(推荐)

用Node.js提供的Promise版本fs.promises,配合async/await让异步代码看起来像同步代码,更易维护:

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

class Game {
  constructor() {
    this.file_data = null;
    // 构造函数不能直接标记为async,用立即执行的async函数包裹初始化逻辑
    (async () => {
      await this.loadDefs();
      this.checkData();
    })();
  }

  async loadDefs() {
    try {
      const data = await fs.readFile('./data.json', 'utf8');
      this.file_data = JSON.parse(data);
      console.log(this.file_data);
    } catch (err) {
      console.error("读取文件失败:", err);
    }
  }

  checkData() {
    if (!this.file_data) {
      console.log("Data not loaded.");
    } else {
      console.log("Data loaded successfully:", this.file_data);
      // 后续业务逻辑写在这里
    }
  }
}

new Game();

如果觉得构造函数里的立即执行async函数不够优雅,可以把初始化逻辑抽成单独方法,外部调用时处理异步:

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

class Game {
  constructor() {
    this.file_data = null;
  }

  async init() {
    await this.loadDefs();
    this.checkData();
  }

  async loadDefs() {
    try {
      const data = await fs.readFile('./data.json', 'utf8');
      this.file_data = JSON.parse(data);
      console.log(this.file_data);
    } catch (err) {
      console.error("读取文件失败:", err);
    }
  }

  checkData() {
    if (!this.file_data) {
      console.log("Data not loaded.");
    } else {
      console.log("Data loaded successfully:", this.file_data);
    }
  }
}

// 外部调用
(async () => {
  const game = new Game();
  await game.init();
})();

关于你尝试的"函数外读取文件再传入"为何失败

如果你的写法是先调用fs.readFile,然后立刻创建Game实例并传入未加载完成的变量,那肯定会失败——因为异步读取还没完成,变量还是空值。正确的写法应该是等文件读取完成后再创建实例:

const fs = require('fs');

fs.readFile('./data.json', 'utf8', (err, data) => {
  if (err) throw err;
  const file_data = JSON.parse(data);
  const game = new Game(file_data); // 此时数据已完全加载,可正常传入
});

class Game {
  constructor(file_data) {
    this.file_data = file_data;
    if (!this.file_data) {
      console.log("Data not loaded.");
    } else {
      console.log("Data loaded successfully:", this.file_data);
    }
  }
}

核心总结

所有依赖异步数据的逻辑,必须等待异步操作完成后再执行,这是Node.js异步编程的核心原则。根据项目复杂度选择回调、Promise或async/await即可解决执行顺序问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 21:50:34