我上传多个文件并保存在某个目录中。我的代码如下
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。我怎样才能做到这一点?
答案 0 :(得分:1)
如果您真的想摆脱异步代码,可以使用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);
});
答案 1 :(得分:1)
我希望使异步函数看起来不那么异步Promises。特别是Bluebird promise library非常好。从本质上讲,您的功能可能如下所示:
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
进行同步,你就可以编写代码“好像”。
答案 2 :(得分:1)
您可以使用多种方法,
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 ) );
})
答案 3 :(得分:1)
@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);
});
希望这会给你一个不同的想法。