albert albert - 1 year ago 154
Javascript Question

Use fse.readFile() inside .map()

I am trying to read the contents of several files in Node.js using promises. Since the standard

fs
module does not provide a sufficient promise interface, I decided to use
fs-extra
instead which provides pretty much the same functions as the default
fs
module with an additional promise interface.

Reading the contents of a single file as shown below works as desired and logs the file's contents to the console:

const fse = require('fs-extra')

const filePath = './foo.txt'


fse.readFile(filePath, 'utf8')
.then(filecontents => {
return filecontents
})
.then(filecontents => {
console.log(filecontents)
})


However, I need to handle several files inside a given directory. To do this I need to implement the following steps:


  1. get an array of all files inside the directory using
    fse.readdir()
    - done

  2. join filenames and directory name to get a kind of a base file path using
    path.join
    with
    .map()
    to avoid iterating over the array - done

  3. read file contents using
    fse.readFile()
    inside another
    .map()



These three steps are implemented as follows:

const fse = require('fs-extra');
const path = require('path');

const mailDirectory = './mails'


fse.readdir(mailDirectory)
.then(filenames => {
return filenames.map(filename => path.join(mailDirectory, filename))
})
.then(filepaths => {
// console.log(filepaths)
return filepaths
.map(filepath => fse.readFile(filepath).then(filecontents => {
return filecontents
}))
})
.then(mailcontents => {
console.log(mailcontents)
})


As stated above, steps 1 and 2 are working quite nice. However, I am unable to read the file contents using
fse.readFile()
inside the last
.map()
which results in an

[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]


output indicating that the promise is not resolved, yet. I assume that this unresolved promise is the promise returned by the
fse.readFile()
function. However I am unable to resolve it properly since a comparable approach in my very first snippet works like a charm.

How could I solve this issue? Where does it exactly come from since I am a newbie in the field of JS and especially in the field of Node.js?

Answer Source

You have an Array of Promises. You should wait on them using Promise.all():

const fse = require('fs-extra');
const path = require('path');

const mailDirectory = './mails'


fse.readdir(mailDirectory)
    .then(filenames => {
        return filenames.map(filename => path.join(mailDirectory, filename))
    })
    .then(filepaths => {
        // console.log(filepaths)
        return filepaths
            .map(filepath => fse.readFile(filepath).then(filecontents => {
                return filecontents
            }))
    })
    // Promise.all consumes an array of promises, and returns a 
    // new promise that will resolve to an array of concrete "answers"
    .then(mailcontents => Promise.all(mailcontents))
    .then(realcontents => {
        console.log(realcontents)
    });

Also, if you don't want to have to have an additional dependency on fs-extra you can use node 8's new util.promisify() to make fs follow a Promise oriented API.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download