【问题标题】:node js async & await functions - force the function to complete?node js async & await 函数 - 强制函数完成?
【发布时间】:2021-05-22 07:17:26
【问题描述】:

我正在尝试使用组件(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 , function(err,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!" };
}

【问题讨论】:

  • 请更新您的问题标题以更详细地反映问题
  • 为什么将uploadFile 设置为async 函数?
  • 不管你有没有,都是一样的。这里的问题是返回发生在 form.parse 完成之前

标签: node.js angular summernote


【解决方案1】:

您不应直接调用在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, function (err, 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 APIfs-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, function (err, fields, 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,
    outputFileName: outputFileName,
    msg: "File uploaded!"
  }
}

不过,您的代码仍然存在一些问题。 outputFileName 被多次分配,这使您的目的难以理解。出于这个原因,我无法重写您的代码,使其符合您的预期。

顺便说一句,应该考虑更多条件。这个我就不多说了。

  • 建议not use var keyword 声明一个局部变量。请改用constlet
  • 避免在 for 循环中使用 await 关键字,除非您打算逐个迭代元素。

【讨论】:

    【解决方案2】:

    最简单的方法是创建一个辅助函数,让 nodestyle fn 返回一个 promise,然后使用它

    function parseMultiparty(req) {
      return new Promise((resolve, reject) => {
        var form = new multiparty.Form();
        form.parse(req, function(err, fields, 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, outputFileName: outputFileName, msg: "File uploaded!" };
    }
    

    【讨论】:

      猜你喜欢
      • 2018-09-23
      • 1970-01-01
      • 2021-08-06
      • 2020-04-13
      • 1970-01-01
      • 2014-02-13
      • 1970-01-01
      • 2018-03-27
      • 2018-05-27
      相关资源
      最近更新 更多