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

但在这段代码中,我遇到了name未定义的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();

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


当前回答

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

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');

其他回答

Node.js 8.0.0

本机异步/等待

Promisify

从这个版本开始,你可以使用来自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()


保证包装

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。

从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

节点v14.0.0及以上版本

你可以这样做:

import { readdir } from "fs/promises";

就像从fs导入一样

更多细节请参见此PR: https://github.com/nodejs/node/pull/31553

从Node 11开始原生支持async/await fs函数

自从Node.JS 11.0.0(稳定)和10.0.0版本(实验)以来,你可以访问已经承诺的文件系统方法,你可以使用它们来处理try catch异常,而不是检查回调的返回值是否包含错误。

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

import fs from 'fs';

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

listDir();

我有一个小的帮助模块,它可以导出fs函数的许诺版本

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

module.exports = {
  readdir: promisify(fs.readdir),
  readFile: promisify(fs.readFile),
  writeFile: promisify(fs.writeFile)
  // etc...
};