在node.js中使用带有async/await的文件系统

Que*_*ber 95 javascript fs node.js async-await

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

但是使用这段代码,我遇到了names未定义的if情况:

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();
Run Code Online (Sandbox Code Playgroud)

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

小智 111

从节点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();
Run Code Online (Sandbox Code Playgroud)

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

  • @makerj他正在使用新的[`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)语法.它目前需要一些转换.也可以使用`const fs = require('fs')`或`const {promisify} = require('util')` (9认同)
  • 在节点v8.9.4中,收到"SyntaxError:Unexpected token import"错误消息.node8默认支持`import`令牌吗? (6认同)
  • @Qasim它被称为解构赋值. (6认同)
  • Noob问题,但是调用的{err,names} = function语法是什么? (2认同)

dim*_*iax 65

Node.js 8.0.0

原生异步/等待

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()

Run Code Online (Sandbox Code Playgroud)

用法

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

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()
Run Code Online (Sandbox Code Playgroud)

  • @VedranMaricevic。看一下评论,“ await”必须始终在“ async”块中:) (2认同)

小智 38

您可能会产生错误的行为,因为File-Api fs.readdir不会返回承诺.它只需要一个回调.如果你想使用async-await语法,你可以'promisify'这个函数:

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

并改为称之为:

names = await readdirAsync('path/to/dir');
Run Code Online (Sandbox Code Playgroud)


bma*_*man 38

自版本10以来,本机异步等待样式fs函数[实验]

从Node.JS 10.0.0开始,您可以访问已经实现的文件系统方法,并且可以将它们与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();
Run Code Online (Sandbox Code Playgroud)

  • @DanStarns如果你不“返回等待”你的承诺,catch块是没有用的......我认为有时在返回之前等待是一个很好的做法 (5认同)
  • 我喜欢做 `import { Promise as fs } from 'fs';` (5认同)

HKT*_*Lee 15

这是问题的 TypeScript 版本。它在 Node 11.0 之后可用:

import { promises as fs } from 'fs';

async function loadMonoCounter() {
    const data = await fs.readFile('monolitic.txt', 'binary');
    return Buffer.from(data);
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*rns 7

You can use fs.Promises

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();
Run Code Online (Sandbox Code Playgroud)

Example using 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);
})();
Run Code Online (Sandbox Code Playgroud)

  • @DavidP 你使用什么版本的节点?12及以上工作正常 (2认同)
  • 是! 完全正确-我忽略了声明的版本:`v10.15.3`-可以禁止显示该消息。但是,由于问题仍然悬而未决,我认为值得一提。 (2认同)

gri*_*son 6

我有这个小帮助模块可以导出函数的promisified版本fs

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

module.exports = {
  readdir: promisify(fs.readdir),
  readFile: promisify(fs.readFile),
  writeFile: promisify(fs.writeFile)
  // etc...
};
Run Code Online (Sandbox Code Playgroud)


Kon*_*rad 6

Node v14.0.0 及以上

你可以这样做:

import { readdir } from "fs/promises";
Run Code Online (Sandbox Code Playgroud)

就像你从 "fs"

有关更多详细信息,请参阅此 PR:https : //github.com/nodejs/node/pull/31553

  • 这应该是 2022 年选定的答案。 (2认同)

Ale*_*aev 5

这对我有用:

const fsp = require('fs-promise');

(async () => {
  try {
    const names = await fsp.readdir('path/to/dir');
    console.log(names[0]);
  } catch (e) {
    console.log('error: ', e);
  }
})();
Run Code Online (Sandbox Code Playgroud)

当启用和声标志时,此代码在没有babel的节点7.6中工作:node --harmony my-script.js.从节点7.7开始,你甚至不需要这个标志!

fsp包含在开头的库只是fs(和fs-ext)的一个有保证的包装器.

这些天我真的已经离开了没有babel的节点你可以做什么!原生async/ await使编写代码非常愉快!

更新2017-06: fs-promise模块已弃用.请fs-extra改用相同的API.


sea*_*078 5

与自定义函数相比,建议使用诸如https://github.com/davetemplin/async-file之类的npm软件包。例如:

import * as fs from 'async-file';

await fs.rename('/tmp/hello', '/tmp/world');
await fs.appendFile('message.txt', 'data to append');
await fs.access('/etc/passd', fs.constants.R_OK | fs.constants.W_OK);

var stats = await fs.stat('/tmp/hello', '/tmp/world');
Run Code Online (Sandbox Code Playgroud)

其他答案已过时