Using filesystem in node.js with async / await
Solution 1
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();
Solution 2
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
Solution 3
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.
Solution 4
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);
})();
Solution 5
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');
Related videos on Youtube
![Quellenangeber](https://lh4.googleusercontent.com/-xB0lqa019n4/AAAAAAAAAAI/AAAAAAAAB90/VKVzQpdOiuo/photo.jpg?sz=256)
Quellenangeber
Updated on July 08, 2022Comments
-
Quellenangeber almost 2 years
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.
-
PirateApp over 6 yearsDownloading a library for this is pure overkill, dependency bloating is something that the community should be strongly against, infact a new npmjs should come into making that only has libs with 0 dependencies
-
makerj over 6 yearsIn node v8.9.4, got a
SyntaxError: Unexpected token import
error message. does node8 supportsimport
token by default? -
Josh Sandlin over 6 years@makerj he's using the new
import
syntax. It currently requires some transpiling. Would be ok to also useconst fs = require('fs')
orconst { promisify } = require('util')
-
Qasim over 6 yearsNoob question, but what's the
{err, names} = function
syntax called? -
jaredkwright over 6 years@Qasim it is called destructuring assignment.
-
Alexander Zeitler about 6 years@jaredkwright The destructuring call results in
Unexpected token =
using Node 10.1.0. -
jaredkwright about 6 years@AlexanderZeitler That may be true. I haven't looked to see if that is actually a correct use of destructuring. In the case of async await I think you would just do
names = await readdir('path/to/dir');
and if there is anerr
handle it in thecatch
block. Either way, the name of the syntax is destructuring assignment which was just in response to Qasim's question. -
Amiga500 almost 6 yearsThis is strange. I am getting SyntaxError: await is only valid in async function... crying in rage.
-
dimpiax almost 6 years@VedranMaricevic. look at comments,
await
must be always inasync
block :) -
Jayraj over 5 years@VedranMaricevic. You need to call that
const res = await readFile('data.json') console.log(res)
in some async function -
TheHanna about 5 yearsThis API is stable as of version 11.x per the File System documentation on the Node.js site
-
Anthony about 5 yearsThis is so ugly, why do the only answers to this question throw errors on every version of node? Is it that hard to add an extra line to destructure longform?
-
DavidP over 4 yearsWorks great, but important to note the open issue regarding the
ExperimentalWarning: The fs.promises API is experimental
warning: github.com/pnpm/pnpm/issues/1178 -
Dan Starns over 4 years@DavidP what version of node are you using? 12 and above works fine
-
DavidP over 4 yearsYes! Absolutely correct - I neglected to state version I am on:
v10.15.3
- it's possible to suppress the message. However, with the issue still open I thought it worth mentioning. -
Dan Starns over 4 years@DavidP I mean it is worth a mention don't get me wrong, but node 12 is in LTS now so it's not a Biggie.
-
oldboy over 4 yearspromise wrapping
fs.promises
and using it withasync/await
is so confusing to me -
dimpiax over 4 years@PrimitiveNom Promise can be used in traditional way within
then
,catch
etc. Where are async/await is modern behavior flow. -
oldboy over 4 yearshow exactly do you use this with, say,
readFile
? im new to this whole promises thing, and all i want to do is have a functiongetContent
that i can call and await in various parts throughout my script, yet this is proving very confusing -
Dan Starns over 4 years@PrimitiveNom you could use fs.promises.readFile I have added a code snippet to my answer.
-
TOPKAT over 4 years@DanStarns if you don't
return await
your promise, the catch block is of no use...I thinj it is sometimes a good practice to await before returning -
Dan Starns over 4 years@538ROMEO just looked into this & your right. Thanks for pointing it out.
-
Jeevan Takhar about 4 yearsDocumentation for these alternative methods: nodejs.org/api/fs.html#fs_fs_promises_api
-
Paula Fleck over 3 yearsI'm getting a weird response like this... 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, 105, 103, 104, 116, 32, 63, 32, 50, 48, 50, 48, 32, 68, 101, 115, 105, 103, 110, 32, 65 …]
-
Jan Aagaard over 3 yearsIn TypeScript (and modern JavaScript?) you can write
import { promises as fs } from "fs";
. -
Dan Starns over 3 years@JanAagaard yeah, you can. There are 2 answers below with import.
-
Muhammed Bera Koç over 3 yearsUse
Buffer.toString
method. -
Jake Wilson over 3 yearsHow come you don't have to put
await
beforefsPromises.readdir(...)
? I thoughtasync/await
have to always be used together. In this case theawait
seems to cause problems. -
Rana Ghosh over 2 yearsi like doing
import { promises as fs } from 'fs';