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()
是同步的,而不是同步的。请参阅我在答案末尾添加的安全说明。谢谢,它工作得很好。谈到路径列表,我在服务器端设置了一个预设的位置。请参阅我在答案末尾添加的安全说明。谢谢,效果很好。谈到路径列表,我在服务器端设置了一个预设位置。