[javascript] Using filesystem in node.js with async / await

I would like to use async/await with some filesystem operations. Normally async/await works fine because I use babel-plugin-syntax-async-functions.

But with this code I run into the if case where names is undefined:

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

When I rebuild the code into the callback hell version everything is OK and I get the filenames. Thanks for your hints.

This question is related to javascript node.js async-await fs

The answer is


This is the TypeScript version to the question. It is usable after Node 11.0:

import { promises as fs } from 'fs';

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

You can use the simple and lightweight module https://github.com/nacholibre/nwc-l it supports both async and sync methods.

Note: this module was created by me.


I have this little helping module that exports promisified versions of fs functions

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

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

Native support for async await fs functions since Node 11

Since Node.JS 11.0.0 (stable), and version 10.0.0 (experimental), you have access to file system methods that are already promisify'd and you can use them with try catch exception handling rather than checking if the callback's returned value contains an error.

The API is very clean and elegant! Simply use .promises member of fs object:

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

Here is what worked for me:

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

This code works in node 7.6 without babel when harmony flag is enabled: node --harmony my-script.js. And starting with node 7.7, you don't even need this flag!

The fsp library included in the beginning is just a promisified wrapper for fs (and fs-ext).

I’m really exited about what you can do in node without babel these days! Native async/await make writing code such a pleasure!

UPDATE 2017-06: fs-promise module was deprecated. Use fs-extra instead with the same API.


Recommend using an npm package such as https://github.com/davetemplin/async-file, as compared to custom functions. For example:

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

Other answers are outdated


As of v10.0, you can use fs.Promises

Example using 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();

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

Node v14.0.0 and above

you can just do:

import { readdir } from "fs/promises";

just like you would import from "fs"

see this PR for more details: https://github.com/nodejs/node/pull/31553


Starting with node 8.0.0, you can use this:

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

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


You might produce the wrong behavior because the File-Api fs.readdir does not return a promise. It only takes a callback. If you want to go with the async-await syntax you could 'promisify' the function like this:

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

and call it instead:

names = await readdirAsync('path/to/dir');

Node.js 8.0.0

Native async / await

Promisify

From this version, you can use native Node.js function from util library.

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 Wrapping

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

Advice

Always use try..catch for await blocks, if you don't want to rethrow exception upper.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to async-await

How to correctly write async method? How can I use async/await at the top level? Any difference between await Promise.all() and multiple await? Async/Await Class Constructor Syntax for async arrow function try/catch blocks with async/await Using filesystem in node.js with async / await Use async await with Array.map Using await outside of an async function SyntaxError: Unexpected token function - Async Await Nodejs

Examples related to fs

Writing JSON object to a JSON file with fs.writeFileSync Using filesystem in node.js with async / await Write / add data in JSON file using Node.js Node.js Write a line into a .txt file NodeJS accessing file with relative path How to create full path with node's fs.mkdirSync? Read file from aws s3 bucket using node fs How to refactor Node.js code that uses fs.readFileSync() into using fs.readFile()? nodejs get file name from absolute path? Node.js check if file exists