-
-
Save qwtel/fd82ab097cbe1db50ded9505f183ccb8 to your computer and use it in GitHub Desktop.
| // Node 8+ | |
| // -------------------------------------------------------------- | |
| // No external dependencies | |
| const { promisify } = require('util'); | |
| const { resolve } = require('path'); | |
| const fs = require('fs'); | |
| const readdir = promisify(fs.readdir); | |
| const stat = promisify(fs.stat); | |
| async function getFiles(dir) { | |
| const subdirs = await readdir(dir); | |
| const files = await Promise.all(subdirs.map(async (subdir) => { | |
| const res = resolve(dir, subdir); | |
| return (await stat(res)).isDirectory() ? getFiles(res) : res; | |
| })); | |
| return files.reduce((a, f) => a.concat(f), []); | |
| } | |
| // Usage | |
| getFiles(__dirname) | |
| .then(files => console.log(files)) | |
| .catch(e => console.error(e)); | |
| // Node 10.10+ | |
| // -------------------------------------------------------------- | |
| // Updated for node 10+ with even more whizbang: | |
| const { resolve } = require('path'); | |
| const { readdir } = require('fs').promises; | |
| async function getFiles(dir) { | |
| const dirents = await readdir(dir, { withFileTypes: true }); | |
| const files = await Promise.all(dirents.map((dirent) => { | |
| const res = resolve(dir, dirent.name); | |
| return dirent.isDirectory() ? getFiles(res) : res; | |
| })); | |
| return Array.prototype.concat(...files); | |
| } | |
| // Note that starting with node 11.15.0 you can use | |
| // `files.flat()` instead of `Array.prototype.concat(...files)` | |
| // to flatten the array. | |
| // Node 11+ | |
| // -------------------------------------------------------------- | |
| // The following version uses async iterators. | |
| const { resolve } = require('path'); | |
| const { readdir } = require('fs').promises; | |
| async function* getFiles(dir) { | |
| const dirents = await readdir(dir, { withFileTypes: true }); | |
| for (const dirent of dirents) { | |
| const res = resolve(dir, dirent.name); | |
| if (dirent.isDirectory()) { | |
| yield* getFiles(res); | |
| } else { | |
| yield res; | |
| } | |
| } | |
| } | |
| // Usage has changed because the return type is now an | |
| // async iterator instead of a promise: | |
| (async () => { | |
| for await (const f of getFiles('.')) { | |
| console.log(f); | |
| } | |
| })() | |
| // I've written more about async iterators here: | |
| // https://qwtel.com/posts/software/async-generators-in-the-wild/ |
That doesn't work properly because it returns unresolved promises. This should work:
What an oversight. I've fixed it in the gist. Thanks for posting a correction.
@qwtel
Great article/examples. Despite having years of embedded multitasking OS development background, Promises just have so many gotchas and ambiguities from my perspective. Still anyway question:
I'm thoroughly confused about the following statements:
const res = resolve(dir, subdir)
Everything I have read is very clear that Promise.resolve() can only return one value. Using any object/array can obviously get around that.
What paradigm allows the above resolve with two parameters? More importantly resolve is undefined (executing under Thunderbird)
with a directory iterator so I had to do some adaptation, but I don't think the resolve question changes.
Thanks
@cleidigh
@cleidigh resolve here is actually path.resolve which takes multiple paths and returns a single value.
Note the const { resolve } = require('path'); in the snippet.
@mrchief
Thanks! I got completely hung up on the resolve and missed the reference to the path module.
I'm trying to adapt this using a Mozilla Thunderbird DirectoryInterator as opposed to readDir.
I have been trying every possible combination of promise handling , but I am obviously flummoxed.
Removing the unnecessary path combination in my case still fails.
I'm going to keep experimenting but I may post my best if I can't get it. This approach is certainly what I need to use just with some tweaks that Confound me.
For example "Node 10.10+":
That doesn't work properly because it returns unresolved promises. This should work: