【问题标题】:Multiple file upload only uploads the first one after using Express File Upload使用快速文件上传后,多个文件上传仅上传第一个文件
【发布时间】:2021-05-22 01:16:09
【问题描述】:

所以我正在开发一个函数,该函数接收从前端的用户输入获取的文件数据数组。这些文件位于req.files.fileInput 中,这是一个文件数据对象数组。

在该函数中,我将遍历该文件数据对象数组以逐个上传。基本上这个想法是,开始上传,如果上传失败,然后通过返回一个带有success: false的对象来停止整个事情。如果所有文件都成功上传,则返回一个带有````success: true```的最终对象。

现在第一个文件被上传并显示带有success: true 的返回对象。而且循环甚至不会转到第二个文件。

req.files 的外观如下:

{
  fileInput: [
    {
      name: '1.jpg',
      data: <Buffer ff d8 ff e0 00 10 44 6f 02 10 00 00 ... 123608 more bytes>,
      size: 123658,
      encoding: '7bit',
      tempFilePath: '',
      truncated: false,
      mimetype: 'image/jpeg',
      md5: '3b8e39e3ed9a26edda2f3713fcb95f4a',
      mv: [Function: mv]
    },
    {
      name: '2.jpg',
      data: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 02 00 00 00 ... 165835 more bytes>,
      size: 165885,
      encoding: '7bit',
      tempFilePath: '',
      truncated: false,
      mimetype: 'image/jpeg',
      md5: '35021d52e7d634042e604fcabf35ccf4',
      mv: [Function: mv]
    }
  ]
}

这是接收req.files.fileInput数组的函数:

const uploadFunc = ( fileDataArr ) => {

    for ( let eachFile of fileDataArr ) {

         const fileName   = eachFile.name;
         const uploadPath = `./images/${fileName}`; 

         return new Promise( ( resolve, reject ) => {

             eachFile.mv( uploadPath, function ( err ) {
                        
                 if ( err ) {
                      return resolve( {
                          success: false,
                          message: 'Something went wrong. Please try again!',
                          data: null
                      });
                  }

             });

             return resolve( {
                  success: true,
                  message: 'Files Uploaded Successfully',
                  data: null
             });

         });
    }

};

uploadFunc(req.files.fileInput);

【问题讨论】:

  • 您试图让您的uploadFunc() 函数返回与fileDataArr 中的文件一样多的次数,但一个函数只能返回一次 - 在这种情况下,它会在第一次返回循环的迭代,这意味着循环实际上在那里结束。
  • @IAmDranged 这种情况怎么办?
  • 您可能可以将整个循环包装在 Promise 执行器函数中,并仅在所有文件实际完成上传时才解析 - 如果需要,使用本地状态变量跟踪迭代计数。请注意,您需要在 mv() 回调函数中异步解析承诺,以便真正等到文件实际完成上传。
  • 更简洁、更易读的方法是将您的代码转换为使用async/await 语法。这需要首先承诺mv() 异步函数——即将它变成一个基于promise 的函数。如果您不熟悉它,请查看它。
  • 如果可以,请提供一个答案,因为我不习惯 JS Promises :(

标签: javascript node.js express


【解决方案1】:

这是一种快速而肮脏的解决方案,但应该可以工作:

  • 将整个循环包装在Promise 执行器函数中。
  • 引入本地 count 状态以跟踪已成功完成的循环迭代次数。
  • 引入isInError 状态以跟踪循环迭代是否失败。
  • 在所有情况下,仅在导致错误的第一次迭代或所有文件已成功完成上传时才解决或拒绝承诺。

const uploadFunc = (fileDataArr) => {
    return new Promise((resolve, reject) => {
        var count = fileDataArr.length
        var isInError = false

        for (let eachFile of fileDataArr) {
            const fileName = eachFile.name;
            const uploadPath = `./images/${fileName}`;

            eachFile.mv(uploadPath, function (err) {
                if (err && !isInError) {
                    isInError = true
                    return resolve({
                        success: false,
                        message: 'Something went wrong. Please try again!',
                        data: null
                    });
                }

                if (--count == 0 && !isInError) {
                    return resolve({
                        success: true,
                        message: 'Files Uploaded Successfully',
                        data: null
                    });
                }
            });
        }
    });
};

请注意,我坚持您在发生错误时解决承诺的逻辑 - 但拒绝实际上可能更有意义,并且实际上在语义上更正确。

正如我在 cmets 中指出的,查找有前途的异步函数和 async/await 语法以获得更简洁的解决方案。

【讨论】:

  • 嘿伙计,你的回答很棒,但我选择了另一个给其他人,因为它看起来更简洁、更易于理解。
  • 当然,没问题。
【解决方案2】:

@IAmDranged 解决方案很棒。但是,您也可以这样做

  • file.mv() 进程移动到自己的promise 函数中,称为fileMoveAsync(file)
  • 映射所有文件并将每个文件传递给fileMoveAsync(file)
  • 使用Promise.all() 等待所有fileMoveAsync(file)
  • 如果Promise.all() 一切顺利,则resolve 否则reject 承诺相应

参见下面的代码。

fileMoveAsync 函数

const fileMoveAsync = async (file) =>
  new Promise((resolve, reject) => {
    const uploadPath = `./resources/images/${file.name}`;
    return file.mv(uploadPath, (err) => {
      if (err) {
        console.error(err);

        return reject({
          success: false,
          message: 'Something went wrong. Please upload again!',
          data: null,
        });
      }

      return resolve({
        success: true,
        message: 'File Uploaded Successfully!',
        data: file.name,
      });
    });
  });
const uploadFunc = async (file) => {
  if (Array.isArray(file)) {
    try {
      const data = await Promise.all(file.map((x) => fileMoveAsync(x)));
      return Promise.resolve({
        success: true,
        message: 'Files Uploaded Successfully!',
        data,
      });
    } catch (e) {
      return Promise.reject({
        success: false,
        message: 'Something went wrong. Please upload again!',
        data: null,
      });
    }
  } else if (typeof file === 'object') {
    return fileMoveAsync(file);
  }
};

这样使用

const { success, message, data } = await uploadFunc(req.files.fileInput);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2018-03-28
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2023-03-26
    相关资源
    最近更新 更多