In the docs it shows two versions of readdir and stat. Both of which have an async and sync version readir/readdirSync
and stat/statSync
.
Because readidir
and stat
are async I would expect them to return a Promise but when trying to use async/await
the script doesnt wait for readdir
to resolve and if I use .then/.catch
I get an error cannot read .then of undefined
.
All I'm trying to do here is map the directories that exist inside of the directory the script is being ran inside of to the dirsOfCurrentDir
map.
Returns error cannot read .then of undefined
const fs = require('fs');
const directory = `${ __dirname }/${ process.argv[2] }`;
const dirsOfCurrentDir = new Map();
fs.readdir(directory, (err, files) => {
let path;
if (err)
return console.log(err);
files.forEach(file => {
path = directory + file;
fs.stat(path, (err, stats) => {
if (err)
return console.log(err);
dirsOfCurrentDir.set(file, directory);
});
});
}).then(() => console.log('adasdasd'))
console.log(dirsOfCurrentDir)
Returns Map {}
const foo = async () => {
await fs.readdir(directory, (err, files) => {
let path;
if (err)
return console.log(err);
files.forEach(file => {
path = directory + file;
fs.stat(path, (err, stats) => {
if (err)
return console.log(err);
dirsOfCurrentDir.set(file, directory);
});
});
});
};
foo()
console.log(dirsOfCurrentDir)
Edit
I ended up going with the synchronous versions of both of these functions readdirSync
and statSync
. While I would feel better using the async methods or promisify I still have not figured out how to get my code working correctly using either.
const fs = require('fs');
const directory = `${ __dirname }/${ process.argv[2] }`;
const dirsOfCurrentDir = new Map();
const dirContents = fs.readdirSync(directory);
dirContents.forEach(file => {
const path = directory + file;
const stats = fs.statSync(path);
if (stats.isDirectory())
dirsOfCurrentDir.set(file, path);
});
console.log(dirsOfCurrentDir); // logs out the map with all properties set
First off, make sure you know the difference between an asynchronous function and an
async
function. A function declared asasync
using that specific keyword in Javascript such as:does always return a promise (per the definition of a function declared with the
async
keyword).But an asynchronous function such as
fs.readdir()
may or may not return a promise, depending upon its internal design. In this particular case, the original implementation of thefs
module in node.js only uses callbacks, not promises (its design predates the existence of promises in node.js). Its functions are asynchronous, but not declared asasync
and thus is uses regular callbacks, not promises.So, you have to either use the callbacks or "promisify" the interface to convert it into something that returns a promise so you can use
await
with it.There is an experimental interface in node.js v10 that offers built-in promises for the fs module.
There are lots of options for promisifying functions in an earlier version of node.js. You can do it function by function using util.promisify():
Since I'm not yet developing on node v10, I often use the Bluebird promise library and promisify the whole fs library at once:
To just list the sub-directories in a given directory, you could do this:
Here's a more general implementation that lists files and offers several options for both what to list and how to present the results:
You can copy this code into a file and run it, passing
.
as an argument to list the directory of the script or any subdirectory name you want to list.If you wanted fewer options (such as no recursion or directory order not preserved), this code could be reduced significantly and perhaps made a little faster (run some async operations in parallel).