reading file with ES6 promises

2020-02-05 07:35发布

问题:

let arr = [];

function getData(fileName, type) {
    return fs.readFile(fileName,'utf8', (err, data) => {
        if (err) throw err;

        return new Promise(function(resolve, reject) {
            for (let i = 0; i < data.length; i++) {
                arr.push(data[i]);
            }

            resolve();
        });
    });
}

getData('./file.txt', 'sample').then((data) => {
    console.log(data);
});

When I use above code and run it in command line using nodejs I get following error.

getData('./file.txt', 'sample').then((data) => {
                               ^

TypeError: Cannot read property 'then' of undefined

How can I solve this?

回答1:

You'll want to wrap the entire fs.readFile invocation inside a new Promise, and then reject or resolve the promise depending on the callback result:

function getData(fileName, type) {
  return new Promise(function(resolve, reject){
    fs.readFile(fileName, type, (err, data) => {
        err ? reject(err) : resolve(data);
    });
  });
}

[UPDATE] As of Node.js v10, you can optionally use the built-in Promise implementations of the fs module by using fs.promises.<API>. In the case of our readFile example, we would update our solution to use fs.promises like this:

function getData(fileName, type) {
  return fs.promises.readFile(fileName, {encoding: type});
}


回答2:

Nobody told about util.promisify so I'm going to post, however old the question is. Why are you having this message?

getData('./file.txt', 'sample').then((data) => {
                               ^

TypeError: Cannot read property 'then' of undefined

getData is a wrapper for fs.readFile file here. fs.readfile is not a thenable (it does not implement a then function). It is built on the other pattern, the callback pattern. The most well-known thenable are Promises, and that's what you want to get from readFile I believe. A little reminder: Mozilla - Promises

So what you can do is either implement it yourself as did @hackerrdave or I would suggest using promisify: this function is a built-in function of Node.js which was implemented to transform the callback-based function into promised based. You will find it here: Node.js Documentation for util.promisfy

It basically does the same as @hackerrdave but it's more robust and built-in node util.

Here's how to use it:

const util = require('util');
const fs = require('fs');

const readFile = util.promisify(fs.readFile)
readFile("path/to/myfile").then(file => console.log(file))


回答3:

Here is a one-liner as of node 10.2.0:

(async () => console.log(String(await require('fs').promises.readFile('./file.txt'))))();

Yes, it is now out of the box.



回答4:

const getData = (fileName, type) =>
  new Promise((resolve, reject) =>
    fs.readFile(fileName, type, (err, data) => {
      //if has error reject, otherwise resolve
      return err ? reject(err) : resolve(data);
    })
  );

getData('./file.txt', 'utf8')
  .then(data => console.log('Data: ', data))
  .catch(error => console.log('Error: ', error));


回答5:

Update for current node As of node 10.0.0 you can now use fs.promises:

const fs = require('fs')

(async function(){
    var fileContents = await fs.promises.readFile(FILENAME)
    var data = JSON.parse(fileContents)
})()