I wanna filter out only the directories in a given path. But in async mode. I have this directory structure:
|-database
|- more files...
|-events-list
|- more files...
|-year-summary
|- more files...
|-year-summary.xlsx
The first three items are subdirectories. I wrote this two functions: ( The double slashes are there because I'm on a windows system)
#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
const dir = 'C:\\Users\\xxx\\Development\\mbes32-events\\src\\reports'
function testSync() {
let items = fs.readdirSync(dir)
let dirs = items.filter(function (item) {
let temp = fs.statSync(path.resolve(dir, item))
return temp.isDirectory()
})
console.log({ dirs })
}
testSync()
result: { dirs: ['database', 'events-list', 'year-summary'] }
async function testAsync() {
let items = await fs.promises.readdir(dir)
let dirs = items.filter(async function (item) {
let temp = await fs.promises.stat(path.resolve(dir, item))
return temp.isDirectory()
})
console.log({ dirs })
}
testAsync()
result: { dirs: ['database', 'events-list', 'year-summary', 'year-summary.xlsx'] }
The snyc function works as expected. But the async function always returns every item from the start path. I want to use the async function because I use a console spinner. To give feedback to the user on large operations. And the spinning is not visible if I use the sync function.
I had it work for a couple of month already. But today my program crashes because of this failure. Is there something I'm missing?
Thanks in advance. :)
CodePudding user response:
looking at your filter function, as you are using async
directly with filter.
The filter function is returned without waiting for the promise to fulfil. That's why non directory items are returned as well.
To use async filter, you may use the following
async function asyncFilter(arr, predicate) {
const results = await Promise.all(arr.map(predicate))
return arr.filter(function (_v, index) {
return results[index]
})
}
async function testAsync() {
let items = await fs.promises.readdir(dir)
let dirs = await asyncFilter(items, async function (item) {
let temp = await fs.promises.stat(path.resolve(dir, item))
return temp.isDirectory()
})
console.log({ dirs })
}
By using a custom async filter function, the expected behavior can be achieved.
There are more options to do this filtering with async, you may refer to this article with detailed explanation.
Disclaimer: the async filter code snippet comes from the article as well. Credits to Tamás Sallai, the author.