Javascript 在节点JS上使用约定

Javascript 在节点JS上使用约定,javascript,node.js,promise,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 => {

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

//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”。
我做错了什么?

您需要向
传递一个函数,然后


目前,您正在立即调用
log
end
,并传递它们的返回值。

您需要将函数传递给
,然后


目前,您正在立即调用
log
end
,并传递它们的返回值。

这里传递两个参数:

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

这里传递两个参数:

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

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

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');

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

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');

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

  • 您没有调用
    resolve(listedFiles)
    来解析承诺,因此它的
    .then()
    处理程序永远不会被调用
  • 您需要将单个函数传递给
    。然后()
  • 您没有异步操作的错误处理
  • 您似乎假设
    fs.stat()
    是同步的,而不是同步的
  • 解决此问题的最佳方法是,预先约定所有异步函数,然后使用承诺来控制流和错误处理。以下是解决所有这些问题的方法:

    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
    的范围限制为仅用于公共消费的特定文件层次结构。

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

  • 您没有调用
    resolve(listedFiles)
    来解析承诺,因此它的
    .then()
    处理程序永远不会被调用
  • 您需要将单个函数传递给
    。然后()
  • 您没有异步操作的错误处理
  • 您似乎假设
    fs.stat()
    是同步的,而不是同步的
  • 解决此问题的最佳方法是,预先约定所有异步函数,然后使用承诺来控制流和错误处理。以下是解决所有这些问题的方法:

    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
    的范围限制为仅用于公共消费的特定文件层次结构。

    这里至少有四个问题:1)您没有调用
    resolve(listedFiles)
    来解析承诺,因此它的
    处理程序永远不会被调用。并且,2)您需要将函数传递给
    。然后()
    。3) 您也没有异步操作的错误处理。并且,4)您似乎假设
    fs.stat()
    是同步的,而不是同步的。这里至少有四个问题:1)您没有调用
    resolve(listedFiles)
    来解析承诺,因此它的
    。然后()
    处理程序永远不会被调用。并且,2)您需要将函数传递给
    。然后()
    。3) 您也没有异步操作的错误处理。而且,4)您似乎假设
    fs.stat()
    是同步的,而不是同步的。请参阅我在答案末尾添加的安全说明。谢谢,它工作得很好。谈到路径列表,我在服务器端设置了一个预设的位置。请参阅我在答案末尾添加的安全说明。谢谢,效果很好。谈到路径列表,我在服务器端设置了一个预设位置。