使用async/await读取Node.js文件

22

我正在尝试使用async/await代码读取文件。这是我的代码:

var fs = require('fs');

function readFile(fileName) {
  return new Promise(resolve => {
    //console.log(test);
    fs.readFile(fileName, 'utf8', function (err, data) {
      if (err) throw err;

      console.log(fileName)
      console.log(data)
    })
    resolve();
  });
}

async function run() {
  await readFile('file1.txt');
  await readFile('file2.txt');
  readFile('file3.txt');
}

run();

但结果仍然是随机的。这意味着file3有时会在file2之前读取。我做错了什么?


2
你把 resolve 放在异步调用的 外面,所以它会立即被解决。 - CertainPerformance
1
可能是如何将现有的回调API转换为Promises?的重复问题。 - CertainPerformance
这回答是否解决了你的问题?使用异步/等待在Node.js中使用文件系统 - KyleMit
2个回答

19

有几种使用本地节点功能的选项

A) 使用fs.promises API

您可以在导入时使用解构分配fs.promises重命名为 fs

const { promises: fs } = require("fs");

(async () => {
    try {
        let file1 = await fs.readFile("file1.txt", "utf-8");
        let file2 = await fs.readFile("file2.txt", "utf-8");

    } catch (e) {
        console.log("e", e);
    }
})()

B) 使用util.promisify API

const fsSync = require("fs");
const {promisify} = require("util")

const fs = {
  readdir: promisify(fsSync.readdir),
  readFile: promisify(fsSync.readFile),
  // etc
};

(async () => {
    try {
        let file1 = await fs.readFile("file1.txt", "utf-8");
        let file2 = await fs.readFile("file2.txt", "utf-8");

    } catch (e) {
        console.log("e", e);
    }
})()

更多阅读材料


19

有许多方法可以实现这一点。

其中大部分在此链接中有解释。


我将编写简单的方法:

1)使用util.promisify将回调方法转换为promise:

const fs = require('fs');
const util = require('util');
const readFile = (fileName) => util.promisify(fs.readFile)(fileName, 'utf8');

(async () => {
  try {
    const files = ['file1.txt', 'file2.txt', 'file3.txt'];
    for (const file of files) {
      console.log(
        await readFile(file)
      );
    }
  }
  catch (error) {
    console.error(error);
  }
})();

2) *Sync 方法。因为您的代码不涉及并发处理,所以可以使用 *Sync 方法:

const fs = require('fs');

try {
  const files = ['file1.txt', 'file2.txt', 'file3.txt'];
  for (const file of files) {
    console.log(
      fs.readFileSync(file, 'utf8')
    );
  }
}
catch (error) {
  console.error(error);
}

顺便提一下,这是您修复后的代码:


var fs = require('fs');

function readFile(fileName) {
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, 'utf8', function (error, data) {
      if (error) return reject(error);

      console.log(fileName)
      console.log(data)

      resolve();
    })
  });
}

async function run() {
  await readFile('file1.txt');
  await readFile('file2.txt');
  await readFile('file3.txt');
}

run();

由于您在同一异步序列中调用了readFileresolve,它们同时被调用,这就是出现竞争条件的原因。

您需要等待回调处理完成,然后再解析它(在回调作用域内)。


1
感谢您展示了其他实现目标的方法... 实际上还有一些额外的代码来处理数据。是的,将resolve()移动到fs.readFile()内部可以使代码正常工作。另外,方案2更易于理解。 - roscoe_x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接