在Node JS上使用promisses

时间:2018-03-02 14:24:52

标签: javascript node.js promise

我正在尝试对此代码使用承诺:

//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))
  )
})

我已经推出了这一行来展示itens列表:

console.log(file)

并在承诺后执行此行:

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

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

4 个答案:

答案 0 :(得分:2)

在这里你通过了两个参数:

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

答案 1 :(得分:1)

您需要将函数传递给then

目前,您正在立即致电logend 并传递其返回值。

答案 2 :(得分:1)

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

  1. 您没有调用resolve(listedFiles)来解析承诺,因此永远不会调用其.then()处理程序
  2. 您需要将单个功能传递给.then()
  3. 您的异步操作没有错误处理
  4. 您似乎假设fs.stat()在不是
  5. 时是同步的

    解决此问题的最佳方法是宣传所有异步函数,然后使用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);
        });
    });
    

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

    您应该将req.body.path的范围限制为仅供公众使用的特定文件hieararchy。

答案 3 :(得分:0)

以下是您的代码的工作副本,我做了一些您可以省略的更改,因为这些只是为了给您一个可用的代码:

var express = require('express');
var fs = require('fs');
var app = express();

app.post('/readList', function(req, res) {
    //Assuming sample data coming in req.body
    //Remove this when you run at you side
    req.body = {
        path: 'temp_dir'
    };

    var cleared = false;
    var listedFiles = [];
    //Promising readList :)
    function readList(){
        return new Promise(function (resolve, reject) {
            // Suppose req.body.path is 'temp_dir' and it has 2 files
            fs.readdir(req.body.path, (err, files) => {
                console.log(files);
            //in following commented code you can do what you need 
            /*files.forEach(file = > {
             console.log(file);
             var fileDetail = {
             name: '',
             local: true,
             filetype: 'fas fa-folder-open',
             filepath: '',
             isFile: false
             }
             if (!cleared) {
             listedFiles = [];
             cleared = true;
             }
             // really? you can think of it later!!
             fileDetail.name = file;
             fileDetail.filepath = req.body.path + file

             // I changed below to avoid surprises for you in data!
             const stats = fs.statSync(req.body.path + file);
             fileDetail.isFile = stats.isFile();
             if (stats.isFile())
             fileDetail.filetype = 'far fa-file-alt';
             else
             fileDetail.filetype = 'fas fa-folder-open'
             listedFiles.push(fileDetail);
             });*/
            resolve(listedFiles);
        });
        });
    }

    readList().then((data) => {
        console.log('vorta');
        // data here will be containing same data as listedFiles so choose your way of doing, I would recommend to go with data
        res.send(JSON.stringify(listedFiles)); // fine
        // res.send(JSON.stringify(data)); // better and recommended
    });
})


app.listen(process.env.PORT || 3000);
console.log('Listening on port 3000');