【问题标题】:reading file with ES6 promises使用 ES6 承诺读取文件
【发布时间】:2017-05-03 08:56:34
【问题描述】:
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);
});

当我使用上面的代码并使用 nodejs 在命令行中运行它时,出现以下错误。

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

TypeError: Cannot read property 'then' of undefined

我该如何解决这个问题?

【问题讨论】:

  • return fs.readFilereturn new Promise() 交换。您正在返回没有返回值的 fs.readFile
  • 你应该使用reject而不是throw
  • 正如 Marty 已经指出的那样,您正在返回 fs.readFile() 的结果,从当前版本的定义来看,这不是 Promise。您可能会感到困惑,因为在 then() 内部可能会返回另一个 Promise,然后将其链接起来。

标签: javascript node.js ecmascript-6 es6-promise


【解决方案1】:

您需要将整个 fs.readFile 调用包装在一个新的 Promise 中,然后根据回调结果拒绝或解决承诺:

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

[更新] 从 Node.js v10 开始,您可以通过使用 fs.promises.&lt;API&gt; 来选择使用 fs 模块的内置 Promise 实现。对于我们的readFile 示例,我们将更新我们的解决方案以使用fs.promises,如下所示:

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

【讨论】:

    【解决方案2】:

    没有人告诉过util.promisify,所以我要发帖,不管问题有多老。 你为什么会收到这条消息?

    getData('./file.txt', 'sample').then((data) => {
                                   ^
    
    TypeError: Cannot read property 'then' of undefined
    

    getDatafs.readFile 文件的包装器。 fs.readfile 不是 thenable(它没有实现 then 函数)。它基于另一个模式,回调模式。最著名的 thenable 是 Promises,我相信这就是你想从readFile 得到的。一点提醒:Mozilla - Promises

    所以你可以做的就是像@hackerrdave 那样自己实现它,或者我建议使用promisify:这个函数是Node.js 的一个内置函数,它的实现是为了将基于回调的函数转换为promise基于。你会在这里找到它:Node.js Documentation for util.promisfy

    它与@hackerrdave 基本相同,但更健壮且内置节点工具。

    使用方法如下:

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

    【讨论】:

    • 我会用const promisify = require('util').promisify; 增强它,然后直接使用promisify(fs.readFile)("path/to/myfile").then( ... )。请记住,正常回调的错误参数不会出现在then 函数中,而是在catch
    • 确实,我会加上catch语句,这样会更清楚。我还将编辑 require 语句,我没有考虑过这一点,但不需要整个 util。
    【解决方案3】:

    这是从节点 10.2.0 开始的单行代码:

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

    是的,它现在是开箱即用的。

    【讨论】:

    • 多行会更好。这很难阅读,V8 编译器会为你做优化。
    • const readFilePromise = async file =&gt; await fs.promises.readFile( file );
    【解决方案4】:

    从 Node 12+ 开始,您可以使用 fs.promises API

    请看下面的例子:

    const { readFile } = require('fs').promises
    
    readFile('./file.txt', { encoding: 'utf8' })
      .then((data) => console.log(data))
      .catch((error) => console.error(error));
    

    使用异步/等待

    const { readFile } = require('fs').promises
    
    async function readFile(filePath) {
      try {
        const data = await readFile(filePath, { encoding: 'utf8' })
        console.log(data)
      } catch (error) {
        console.error(error.message)
      }
    }
    
    readFile('./file.txt')
    

    【讨论】:

    • 此答案自 11+ 起有效,可能为 10+,但早在 11.0 就已针对 async/await 部分进行了验证:) - 也就是说,比此答案中引用的版本更早
    【解决方案5】:
    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));
    

    【讨论】:

    • 看来内部return 可能会更混淆OP?
    • 我认为你需要 return new Promise 行,否则 getData 不会有 then 定义。
    • @counterbeing return 对于没有大括号的箭头函数是隐含的。
    【解决方案6】:

    当前节点更新从节点 10.0.0 开始,您现在可以使用 fs.promises

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-25
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      • 1970-01-01
      • 2016-11-20
      • 2018-11-28
      • 2016-06-13
      相关资源
      最近更新 更多