Sekhemty
Sekhemty

Reputation: 1562

How to correctly manipulate and return an array of files with node?

Given a directory containing markdown files, i.e.

myDir
|- fileA.md
|- fileB.md
|- fileC.md
|- fileD.md

I'm trying to create an array of these files, by also stripping the file extension.

I'm trying with this:

var mdFiles = fs.readdir('myDir', (err, files) => {

    const filesNoExt = []

    files.forEach( file => {      
        filesNoExt.push(file.slice(0, -3)
    })
    return filesNoExt
});

console.log(mdFiles)

but the result of the console.log command is undefined.

If I modify this script like this (so, by adding a console.log inside the readdir function):

var mdFiles = fs.readdir('myDir', (err, files) => {

    const filesNoExt = []

    files.forEach( file => {      
        filesNoExt.push(file.slice(0, -3)
    })
    console.log(filesNoExt)
});

console.log(mdFiles)

here is what I get:

undefined
[
  'fileA',
  'fileB',
  'fileC',
  'fileD'
]

The first line is undefined exactly like before, but then it is also printed the result of the console.log inside the function, which shows that the filesNoExt array is correctly populated with the stripped filenames.

How can I correctly return the filesNoExt array from the mdFiles function, so that I can access its content also from outside?

Upvotes: 0

Views: 440

Answers (2)

D. Pardal
D. Pardal

Reputation: 6597

The callback you passed to fs.readdir happens asynchronously (after the call stack empties), so there is no way that you can get its return value like that. In fact, the return value is ignored. You can use this:

fs.readdir('myDir', (err, files) => {
    const filesNoExt = [];

    files.forEach( file => {      
        filesNoExt.push(file.slice(0, -3)
    });

    console.log(mdFiles)
});

Or you can use promises like this:

(async ()=>{

  const mdFiles = await fs.promises.readdir('myDir');

  files.forEach( file => {      
    filesNoExt.push(file.slice(0, -3)
  });

  console.log(mdFiles);
})();

If you are doing other asynchronous actions (e.g. using setTimeout) you should not use the synchronous variants of fs functions (like fs.readdirSync) because they will block the program (main thread) while executing the action.

Upvotes: 1

Aplet123
Aplet123

Reputation: 35560

The reason it's not working is because readdir is an asynchronous function, which means it runs in parallel to the rest of your code. If you want to block execution, use readdirSync:

var mdFiles = fs.readdirSync('myDir');
const filesNoExt = [];
mdFiles.forEach(file => {      
    filesNoExt.push(file.slice(0, -3)
});
console.log(filesNoExt);

Upvotes: 3

Related Questions