在Node JS中使用promises

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Node JS中使用promises相关的知识,希望对你有一定的参考价值。

我正试图在这段代码上使用一个承诺:

//Listando arquivos
app.post('/readList', function(req, res) {
  var cleared = false
  var readList = new Promise(function(resolve, reject){
      fs.readdir(req.body.path, (err, files) => {
        files.forEach(file => {
          console.log(file)
          var fileDetail = {
            name: '',
            local: true,
            filetype: 'fas fa-folder-open',
            filepath: '',
            isFile: false
          }
          if(!cleared){
            listedFiles = []
            cleared = true
          }
          fileDetail.name = file
          fileDetail.filepath = req.body.path + file
          fs.stat(req.body.path + file, function(err, stats) {
            fileDetail.isFile = stats.isFile()
            if(stats.isFile()) fileDetail.filetype = 'far fa-file-alt'
            else fileDetail.filetype = 'fas fa-folder-open'
          })
          listedFiles.push(fileDetail)
        })
      })    
  })
  readList.then(
    console.log('vorta'),
    res.end(JSON.stringify(listedFiles))
  )
})

我已经推出这一行来显示列出的项目:

console.log(file)

在承诺之后将此行执行:

readList.then(
  console.log('vorta'),
  res.end(JSON.stringify(listedFiles))
)

我不知道哪里出错,但是控制台在文件名之前显示'vorta'。我究竟做错了什么?

答案

正如我在之前的评论中所说,这里至少存在四个问题:

  1. 你没有调用resolve(listedFiles)来解决这个问题所以它的.then()处理程序永远不会被调用
  2. 你需要将一个函数传递给.then()
  3. 您没有异步操作的错误处理
  4. 你似乎假设fs.stat()是同步的,当它不是

解决此问题的最佳方法是宣传所有异步函数,然后使用promises来控制流和错误处理。这是解决所有这些问题的方法:

const util = require('util');
const fs = require('fs');
const readdirAsync = util.promisify(fs.readdir);
const statAsync = util.promisify(fs.stat);

//Listando arquivos
app.post('/readList', function(req, res) {
    // add code here to sanitize req.body.path so it can only
    // point to a specific sub-directory that is intended for public consumption
    readdirAsync(req.body.path).then(files => {
        return Promise.all(files.map(file => {
            let fileDetail = {
                name: file,
                local: true,
                filepath: req.body.path + file
            };
            return statAsync(fileDetail.filepath).then(stats => {
                fileDetail.isFile = stats.isFile();
                fileDetail.filetype = fileDetail.isFile ? 'far fa-file-alt' : 'fas fa-folder-open';
                return fileDetail;
            });
        }));
    }).then(listedFiles => {
        res.json(listedFiles);
    }).catch(err => {
        console.log(err);
        res.sendStatus(500);
    });
});

仅供参考,这是一种危险的实现,因为它列出了用户传入的任何路径上的文件,因此任何局外人都可以在服务器的硬盘上看到整个文件列表。它甚至可以列出网络连接的驱动器。

您应该将qazxsw poi的范围限制为仅供公众使用的特定文件层次结构。

另一答案

在这里你传递两个参数:

req.body.path

所以,你需要传递一个函数

readList.then(
   //#1 In this case you're executing the log function and cause that the message is being printed.
   console.log('vorta'), 
   res.end(JSON.stringify(listedFiles)) //# 2
)

此外,您需要在异步逻辑中调用函数readList.then(function() { console.log('vorta'); res.end(JSON.stringify(listedFiles)); })

另一答案

你需要将一个函数传递给resolve

就目前而言,您立即调用thenlog并传递其返回值。

另一答案

这是您的代码的工作副本,我做了一些您可以省略的更改,因为这些只是为您提供一个有效的代码:

end

以上是关于在Node JS中使用promises的主要内容,如果未能解决你的问题,请参考以下文章

Node.js:何时使用 Promises 与 Callbacks

如何在Node.js中对使用promises和事件发射器的函数进行单元测试?

使用 Q Promise 的 node.js 项目的代码覆盖率

如何使用 Promise 和 node.js 正确检查和记录 http 状态代码?

VSCode自定义代码片段12——JavaScript的Promise对象

VSCode自定义代码片段12——JavaScript的Promise对象