问题描述
我正在尝试使用组件(summernote)以角度形式上传图像。
我配置了 uploadImagePath
端点以将图像提交到我的 nodejs 后端,但在我的代码中,outputFileName
字段返回空。
如何确保功能完成?
async uploadFile(req) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
let outputFileName = '';
try {
form.parse(req,function(err,fields,files) {
var imgArray = files.image;
for (var i = 0; i < imgArray.length; i++) {
var singleImg = imgArray[i];
outputFileName = singleImg.originalFilename;
fs.readFile(singleImg.path,data) {
fs.writeFile('./public/images/'+outputFileName,data,function(err) {
if (err) console.log('ERRRRRR!! :'+err);
console.log('Fitxer: ' + outputFileName);
})
})
}
});
}
catch (ex) {
throw ex;
}
return { error: false,outputFileName: outputFileName,msg: "File uploaded!" };
}
解决方法
您不应在 async
函数中直接调用接受回调的函数。这就是为什么您的 try-catch 捕获任何错误的机会较小的原因。相反,返回一个 Promise
来处理该错误。
function uploadFile(req) {
return new Promise((resolve,reject) => {
const multiparty = require('multiparty')
const form = new multiparty.Form()
let outputFileName = ''
form.parse(req,function (err,fields,files) {
if (err) {
reject(err)
return
}
const imgArray = files.image
// You should not call function that accepts a callback in for loop
// Lets assumed imageArray has only one element.
// for (let i = 0; i < imgArray.length; i++) {
const singleImg = imgArray[0 /* i */]
outputFileName = singleImg.originalFilename
fs.readFile(singleImg.path,data) {
if (err) {
reject(err)
return
}
fs.writeFile('./public/images/' + outputFileName,data,function (err) {
if (err) {
reject(err)
return
}
console.log('Fitxer: ' + outputFileName)
resolve({
error: false,outputFileName: outputFileName,msg: "File uploaded!"
})
})
})
// }
});
})
}
但是如您所见,上面的代码很乱,for 循环不起作用。为了解决这个问题,我们应该使 uploadFile
异步,不能使用回调。
如果可能,async
函数应该调用另一个返回 Promise
的函数,这样 await
关键字有助于简化代码并处理抛出的错误。要实现这样的用法,请编写一个新函数来使 form.parse
异步,并将 fs
替换为支持返回 Promise
的东西,例如 fs.Promise
API 或 fs-extra
package .
const fs = require('fs-extra')
const multiparty = require('multiparty')
function parseForm(req) {
return new Promise((resolve,reject) => {
const form = new multiparty.Form()
form.parse(req,files) {
if (err) reject(err)
else resolve(files)
})
})
}
async function uploadFile(req) {
let outputFileName = ''
const files = await parseForm(req)
const imgArray = files.image
// Now we can use for loop
for (let i = 0; i < imgArray.length; i++) {
const singleImg = imgArray[i]
outputFileName = singleImg.originalFilename
const data = await fs.readFile(singleImg.path)
await fs.writeFile('./public/images/' + outputFileName,data)
console.log('Fitxer: ' + outputFileName)
}
return {
error: false,msg: "File uploaded!"
}
}
您的代码仍然存在一些问题。 outputFileName
被多次分配,这使您的目的难以理解。因此,我无法按照您的预期重写您的代码。
顺便说一句,应该考虑更多条件。这个我就不多说了。
- 建议使用 not use
var
keyword 声明一个局部变量。改用const
或let
。 - 避免在 for 循环中使用
await
关键字,除非您打算一个一个地迭代元素。
最简单的方法是创建一个辅助函数,让 nodestyle fn 返回一个 promise,然后使用它
function parseMultiparty(req) {
return new Promise((resolve,reject) => {
var form = new multiparty.Form();
form.parse(req,function(err,files) {
if(err) reject(err) else resolve([fields,files])
})
})
}
async uploadFile(req) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
let outputFileName = '';
try {
const [fields,files] = await parseMultiparty(req)
var imgArray = files.image;
for (var i = 0; i < imgArray.length; i++) {
var singleImg = imgArray[i];
outputFileName = singleImg.originalFilename;
const data = await fs.promises.readFile(singleImg.path)
console.log('Fitxer: ' + outputFileName);
try {
await fs.promises.writeFile('./public/images/'+outputFileName,data)
} catch(err) { console.log('ERRRRRR!! :'+err);}
}
}
catch (ex) {
throw ex;
}
return { error: false,msg: "File uploaded!" };
}