0

I am attempting to loop through an array containing directories and then return a combined array of all the items regardless of the number of directories. I was attempting to use the fs.readdir function to read the directories, but seeing as the fs.readdir function is an async function I can't pass the information back out of it.

Is there a way to use this function, but also make an array of the directory listings?

This is what I would like to do, but I know that this is just wrong. Hoping for a little guidance. I can provide any additional info. Thank you.

var docs = [];
libs.forEach(function(lib){
    fs.readdir(lib, function(err, files){
        files.forEach(function(file){
            docs.push(file);
        });
    });
});
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
John Moran
  • 43
  • 6
  • You can [learn async programming](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) or you can use [readdirSync](https://nodejs.org/api/fs.html#fs_fs_readdirsync_path_options) – Adam Jenkins Sep 26 '20 at 20:13
  • I am attempting to learn Async, but it is taking some time to wrap my head around. I thought about using the sync version, but I don't want to tie up the app while this function runs. – John Moran Sep 26 '20 at 20:19
  • If you're worried about performance, then use the async answer in the linked comment. – Adam Jenkins Sep 26 '20 at 20:20
  • I will look into it further. I appreciate the guidance. – John Moran Sep 26 '20 at 20:23
  • 1
    Keep in mind that node ships with a [promise based fs api](https://nodejs.org/api/fs.html#fs_ordering_of_callback_and_promise_based_operations). Most async examples you'll find use promises/async-await so using the `fs/promises` will probably be easier to compare to similar code snippets – Adam Jenkins Sep 26 '20 at 20:25
  • @JohnMoran My answer doesn't work, sorry and thanks for your time. – Praveen Kumar Purushothaman Sep 26 '20 at 20:27

1 Answers1

1

An async version:

const fs = require("fs/promises");

function listDirectories(dirs) {
  return Promise.all(dirs.map(dir => fs.readdir(dir))).then(files => files.flat());
}

It maps an array of strings (directories) into an array of promises returned by fs.readdir, followed by flattening the results of those promises once they resolve using Array.prototype.flat. Flattening is required to transform this:

[ [ "file1" ], [ "file2", "file3" ] ] into [ "file1", "file2", "file3" ].

Then, from an async function you can call it like so:

(async () => {
  const dirs = ["one", "two", "three"];
  try {
    let files = await listDirectories(dirs);
    console.log(files);
  } catch (e) {
    console.error(e);
  }
})();

Note that the above is an IIFE (Immediately Invoked Function Expression) that you can use to test the function without having to integrate it into your codebase first.

Sven
  • 5,155
  • 29
  • 53
  • This looks promising. I will have to give it a go. Thanks! – John Moran Sep 26 '20 at 21:02
  • Your assistance here basically unlocked the rest of the function I was working on. Thank you. I am not an experienced programmer, but I am trying to learn, and I have literally been stuck in this Hell for two days. Helped to clarify some async principles for me as well. – John Moran Sep 27 '20 at 02:34
  • @JohnMoran Glad I could help, keep at it! – Sven Sep 27 '20 at 08:35