在 node.js 中使用文件系统与 async / await

IT技术 javascript node.js async-await fs
2021-01-13 12:54:06

我想对一些文件系统操作使用 async/await。通常 async/await 工作正常,因为我使用babel-plugin-syntax-async-functions.

但是使用此代码,我遇到了 ifnames未定义的情况:

import fs from 'fs';

async function myF() {
  let names;
  try {
    names = await fs.readdir('path/to/dir');
  } catch (e) {
    console.log('e', e);
  }
  if (names === undefined) {
    console.log('undefined');
  } else {
    console.log('First Name', names[0]);
  }
}

myF();

当我将代码重建到回调地狱版本中时,一切正常,我得到了文件名。谢谢你的提示。

6个回答

从节点 8.0.0 开始,您可以使用:

const fs = require('fs');
const util = require('util');

const readdir = util.promisify(fs.readdir);

async function myF() {
  let names;
  try {
    names = await readdir('path/to/dir');
  } catch (err) {
    console.log(err);
  }
  if (names === undefined) {
    console.log('undefined');
  } else {
    console.log('First Name', names[0]);
  }
}

myF();

https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original

菜鸟问题,但{err, names} = function语法叫什么?
2021-03-18 12:54:06
在节点 v8.9.4 中,收到SyntaxError: Unexpected token import错误消息。node8import默认支持令牌吗?
2021-04-02 12:54:06
@AlexanderZeitler 这可能是真的。我还没有看这是否实际上是对解构的正确使用。在 async await 的情况下,我认为你会这样做names = await readdir('path/to/dir');,如果块中有一个err句柄catch无论哪种方式,语法的名称都是解构赋值,这只是为了回应 Qasim 的问题。
2021-04-07 12:54:06
@makerj 他正在使用新import语法。它目前需要一些转换。也可以使用const fs = require('fs')const { promisify } = require('util')
2021-04-09 12:54:06
@Qasim 它被称为解构赋值。
2021-04-11 12:54:06

自 Node 11 起对 async await fs 函数的原生支持

从 Node.JS 11.0.0(稳定版)和 10.0.0 版(实验版)开始,您可以访问已经Promise的文件系统方法,并且可以将它们用于try catch异常处理,而不是检查回调的返回值是否包含一个错误。

API 非常干净和优雅!只需使用对象.promises成员fs

import fs from 'fs';
const fsPromises = fs.promises;

async function listDir() {
  try {
    return fsPromises.readdir('path/to/dir');
  } catch (err) {
    console.error('Error occured while reading directory!', err);
  }
}

listDir();
@538ROMEO 刚刚调查了这个和你的权利。谢谢你指出。
2021-03-20 12:54:06
这些替代方法的文档:nodejs.org/api/fs.html#fs_fs_promises_api
2021-03-20 12:54:06
根据 Node.js 站点上的文件系统文档此 API 从版本 11.x 开始是稳定的
2021-03-21 12:54:06
为什么你没有把await之前fsPromises.readdir(...)我想async/await必须总是一起使用。在这种情况下,await似乎会引起问题。
2021-04-05 12:54:06
@DanStarns 如果你不return awaitPromise,catch 块是没有用的......我认为有时在返回之前等待是一个好习惯
2021-04-10 12:54:06

Node.js 8.0.0

本机异步/等待

Promise

从这个版本开始,你可以使用util库中的原生 Node.js 函数

const fs = require('fs')
const { promisify } = require('util')

const readFileAsync = promisify(fs.readFile)
const writeFileAsync = promisify(fs.writeFile)

const run = async () => {
  const res = await readFileAsync('./data.json')
  console.log(res)
}

run()


Promise包装

const fs = require('fs')

const readFile = (path, opts = 'utf8') =>
  new Promise((resolve, reject) => {
    fs.readFile(path, opts, (err, data) => {
      if (err) reject(err)
      else resolve(data)
    })
  })

const writeFile = (path, data, opts = 'utf8') =>
  new Promise((resolve, reject) => {
    fs.writeFile(path, data, opts, (err) => {
      if (err) reject(err)
      else resolve()
    })
  })

module.exports = {
  readFile,
  writeFile
}

...


// in some file, with imported functions above
// in async block
const run = async () => {
  const res = await readFile('./data.json')
  console.log(res)
}

run()

建议

try..catch如果您不想重新抛出异常,请始终用于等待块。

@PrimitiveNomPromise可以在传统的方式中使用thencatch等哪里异步/ AWAIT是现代行为流。
2021-03-14 12:54:06
@VedranMaricevic。查看评论,await必须始终在async块中:)
2021-03-19 12:54:06
@VedranMaricevic。你需要const res = await readFile('data.json') console.log(res)在一些异步函数中调用它
2021-03-21 12:54:06
这很奇怪。我收到 SyntaxError: await is only valid in async function... 愤怒地哭泣。
2021-04-02 12:54:06
Promise包装fs.promises和使用它async/await让我很困惑
2021-04-09 12:54:06

v10.0 开始,您可以使用fs.Promises

使用示例 readdir

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

async function myF() {
    let names;
    try {
        names = await fs.readdir("path/to/dir");
    } catch (e) {
        console.log("e", e);
    }
    if (names === undefined) {
        console.log("undefined");
    } else {
        console.log("First Name", names[0]);
    }
}

myF();

使用示例 readFile

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

async function getContent(filePath, encoding = "utf-8") {
    if (!filePath) {
        throw new Error("filePath required");
    }

    return fs.readFile(filePath, { encoding });
}

(async () => {
    const content = await getContent("./package.json");

    console.log(content);
})();
效果很好,但重要的是要注意有关ExperimentalWarning: The fs.promises API is experimental警告的未解决问题github.com/pnpm/pnpm/issues/1178
2021-03-15 12:54:06
是的!绝对正确 - 我忽略了我使用的版本:v10.15.3- 可以抑制消息。然而,在这个问题仍然存在的情况下,我认为值得一提。
2021-03-17 12:54:06
在 TypeScript(和现代 JavaScript?)中,您可以编写import { promises as fs } from "fs";.
2021-03-19 12:54:06
@DavidP 我的意思是值得一提,不要误会我的意思,但是节点 12 现在在 LTS 中,所以它不是一个大人物。
2021-03-30 12:54:06
@DavidP 您使用的是什么版本的节点?12 及以上工作正常
2021-04-01 12:54:06

您可能会产生错误的行为,因为 File-Apifs.readdir不返回Promise。它只需要一个回调。如果你想使用 async-await 语法,你可以像这样“Promise”这个函数:

function readdirAsync(path) {
  return new Promise(function (resolve, reject) {
    fs.readdir(path, function (error, result) {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
  });
}

并改为调用它:

names = await readdirAsync('path/to/dir');
我得到了这样一个奇怪的响应...... Buffer(18524) [60, 115, 99, 114, 105, 112, 116, 32, 116, 110, 116, 45, 108, 105, 98, 62, 13 , 10, 32, 32, 32, 32, 47, 42, 42, 13, 10, 32, 32, 32, 32, 32, 42, 32, 67, 111, 112, 121, 114, 1030 10 , 116, 32, 63, 32, 50, 48, 50, 48, 32, 68, 101, 115, 105, 103, 110, 32, 65 …]
2021-03-17 12:54:06
使用Buffer.toString方法。
2021-03-25 12:54:06