[英]How to avoid async behviour of node.js?
我正在上传多个文件并保存在某个目录中。 我的代码如下
app.post('/file_upload', function (req, res) {
var msgs = '';
req.files.forEach(function(element) {
var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname;
fs.readFile( element.path, function (err, data) {
fs.writeFile(fileNameToWrite, data, function (err) {
if( err ){
msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' ";
}
else{
msgs += element.originalname + " Uploaded Successfully ";
}
});
});
},this);
console.log("Final Msgs: " + msgs);
res.end( JSON.stringify( msgs ) );
});
问题是msgs异步填充,一旦forEach完成,我想获取msgs。 我该如何实现?
如果您确实想摆脱异步代码,则可以使用writeFileSync
和readFileSync
。 但这不是一个好习惯。
一种简单的方法是使用这样的回调:
app.post('/file_upload', function (req, res) {
var msgs = '';
function finish() {
console.log("Final Msgs: " + msgs);
res.end( JSON.stringify( msgs ) );
}
var counter = 0;
req.files.forEach(function(element) {
var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname;
fs.readFile( element.path, function (err, data) {
fs.writeFile(fileNameToWrite, data, function (err) {
if( err ){
msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' ";
}
else{
msgs += element.originalname + " Uploaded Successfully ";
}
// We call the finish when we write the last file
counter += 1;
if (counter == req.files.length) {
finish();
}
});
});
},this);
});
我希望使异步函数看起来不那么异步的是Promises 。 尤其是Bluebird Promise库非常出色。 本质上,您的函数可能如下所示:
var Promise = require('bluebird')
var readFile = Promise.promisify(require('fs').readFile);
app.post('/file_upload', function (req, res) {
var msgs = '';
req.files.forEach(function(element) {
var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname;
readFile(element.path).then(function (data) {
return writeFile(filenameToWrite, data);
}).then(function () {
msgs += element.originalname + " Uploaded Successfully ";
}).catch(function () {
msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' ";
}).then(function () {
console.log("Final Msgs: " + msgs);
res.end( JSON.stringify( msgs ) );
});
},this);
});
这样可以保持异步调用的所有优势(例如,不锁定运行线程),从而使您的API快速响应。 不过,如果仅通过链接then
同步,它仍可以让您编写代码“好像”。
您可以使用几种方法,
1.使用writefilesync
代替fs.writeFile
,像这样
req.files.forEach(function(element) {
var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname;
try {
fs.writeFileSync(fileNameToWrite, data);
msgs += element.originalname + " Uploaded Successfully ";
} catch(err) {
msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' ";
}
}, this);
2,或者使用像async
( npm i async --save-dev
)这样的库
var async = require('async');
var msgs = '';
async.eachSeries(req.files, function (element, next) {
var fileNameToWrite = __dirname + "\\uploads\\" + element.originalname;
fs.readFile(element.path, function (err, data) {
if (err) {
msgs += element.originalname + " Uploaded Failed Error: '"+ err +"' ";
} else {
msgs += element.originalname + " Uploaded Successfully ";
}
next();
});
}, function () {
console.log("Final Msgs: " + msgs);
res.end( JSON.stringify( msgs ) );
})
@Nomi我建议更改以下内容,这将帮助您获得很多性能。
1.将文件上传从单个发布请求更改为多个发布请求。 我的意思是,您应该更改前端代码以将单独的后期请求发送到每个文件。
2.在每个JavaScript请求中保留跟踪器/计数变量。 基本上,计数器值最初与文件数相同。 每个文件完全上传后,再减少1。 并且当计数器值达到0时,您可以显示成功消息。可能的是,您可以使用promise进行此文件跟踪。
3.修改您的服务器端代码,以流式处理文件上传请求。 您可能需要查看以下服务器端代码。
var fs = require('fs');
app.post('/file_upload', function(req, res) {
// Read file name and extension from request header and replace 'somefile.someExtension' below.
var fileNameToWrite = __dirname + "\\uploads\\" + 'somefile.someExtension';
var wStream = fs.createWriteStream(fileNameToWrite);
req.pipe(wStream);
});
希望这会给您一个替代的主意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.