Reputation: 73
I want to log all the files in the directory recursively and return a confirmation when all files are logged. Here's the directory structure.
sample
│ app.js
└───Temp1
│ │ temp1.js
│ └───Temp2
│ │ temp2.js
Here's the code
```
let readDirectory = function(dirname){
return new Promise((resolve,reject)=>{
fs.readdir(dirname,(err,files)=>{
if(err) reject(err);
files.forEach(file=>{
fs.stat(`${dirname}/${file}`,(err,stats)=>{
if(stats.isDirectory()){
readDirectory(`${dirname}/${file}`)
}else{
resolve(console.log(file));
}
})
})
})
})
}
readDirectory(sampledir).then(()=>console.log('completed'));
```
Below is the result when I execute this function.
```
app.js
completed
temp1.js
temp2.js
```
Where should I resolve in order to get output as below.
```
app.js
temp1.js
temp2.js
completed
```
Upvotes: 4
Views: 130
Reputation: 370619
You need to resolve only after Promise.all
resolves over every file. Also, you need to resolve each directory promise only after each file in the directory is finished:
let readDirectory = function(dirname) {
return new Promise((resolveAll, rejectAll) => {
fs.readdir(dirname, (err, files) => {
if (err) rejectAll(err);
})
}).then((files) => {
const filesPromises = files.map(file => (
new Promise((resolveFile, rejectFile) => {
fs.stat(`${dirname}/${file}`, (err, stats) => {
if (err) rejectFile(err);
if (stats.isDirectory()) {
readDirectory(`${dirname}/${file}`)
.then(resolveFile);
.catch(rejectFile);
} else {
resolveFile(console.log(file));
}
})
})
));
return Promise.all(filesPromises).then(resolveAll);
});
}
Note that this is pretty difficult to make sense of - you'll be far better off using async
/await
instead, something like this:
let readDirectory = async function(dirname) {
const files = await new Promise((resolve, reject) => {
fs.readdir(dirname, (err, files) => {
if (err) reject(err);
resolve(files);
});
});
const filesPromises = files.map(async (file) => {
const stats = await new Promise((resolve, reject) => {
fs.stat(`${dirname}/${file}`, (err, stats) => {
if (err) reject (err);
else resolve(stats);
});
});
if (stats.isDirectory()) await readDirectory(`${dirname}/${file}`);
else console.log(file);
});
return Promise.all(filesPromises);
}
Upvotes: 3
Reputation: 1513
If you're using Node 8 or later, you can promisify to improve readability:
const util = require('util')
const fs = require('fs')
const stat = util.promisify(fs.stat)
const readdir = util.promisify(fs.readdir)
let readDirectory = (dirname) =>
readdir(dirname).then(files =>
Promise.all(files.map(file =>
stat(`${dirname}/${file}`).then(stats =>
stats.isDirectory() ? readDirectory(`${dirname}/${file}`) :
console.log(file)
)
))
)
readDirectory(__dirname).then(() => {
console.log('Completed')
})
Or a super simplified version with async/await:
let readDirectory = async dirname =>
await Promise.all((await readdir(dirname)).map(async file =>
(await stat(`${dirname}/${file}`)).isDirectory() ?
readDirectory(`${dirname}/${file}`) : console.log(file)
))
Upvotes: 3