循环异步调取接口使用数组promiseList保存,Promise.all(promiseList)获取不到数组内容,then()返回空数组

在使用 vue + [email protected] 技术栈的项目中,因为上传文件的接口是单文件上传,当使用批量上传时,只能循环调取接口;然后有校验内容:需要所有文件上传成功后才能保存,在文件上传不成功时点击保存按钮,则提示信息:"文件上传未成功!"

我使用 for 循环调取接口,然后定义了 promiseList 数组,循环一次将 promise 对象添加一次,然后使用 Promise.all(promiseList).then(result=>console.log(result)) 来改变保存的状态。但是发现打印出的 result 总是空数组[]。debugger 代码的执行顺序,应该是异步的原因导致的。

如下代码:

js 复制代码
/** 上传文件组件 */
<van-uploader
  name="multipartFile"
  multiple
  v-model="jobFileList"
  :after-read="(file) => afterRead(file, jobFileList)"  // 默认写法参数只有file对象,如需传递其他参数则需要此种写法
  :before-read="(file) => beforeRead(file, jobFileList)"
  :before-delete="(file) => beforeDelete(file, jobFileList)"
  :max-count="9"
>
</van-uploader>

下面上传了一张图片文件格式;如下图,其中 fileId、fileName、fileType、fileUrl 为自定义字段,上传服务器成功后返回的,其他字段为 van-uploader 组件所支持的自有字段。

js 复制代码
/** 上传文件逻辑 */
afterRead(file) {
  const _this = this;
  this.isFetchDone = 1; // 文件是否全部上传完成:0是 1否
  let promiseList = [];
  if (!Array.isArray(file)) {
    // 单张图片上传
    promiseList = [file];
  } else {
  	// 批量上传
    promiseList = file;
  }
  for (const f of file) {
  	// 压缩文件
    new Compressor(f.file, {
      quality: 0.5,
      success(result) {
        // blob格式转换为file格式
        f.file= new File([result], result.name, { type: result.type });
        const p = _this.uploadFileChange(f);
        promiseList.push(p);
      },
      error(err) {
        console.warn(err.message);
      },
    });
  }
  // 使用Promise.all()改变保存状态
  Promise.all(promiseList).then(result=> {
    console.log(result);  // []
    // 所有的文件状态都是"done"则代表文件全部上传完成 
    const bool = result.every(file => file.status === 'done');
     if (bool) {
       // 改变保存状态为0,可保存
       this.isFetchDone = 0;
     }
   })
}
/** 上传文件逻辑 */
uploadFileChange(f) {
  return new Promise((resolve, reject) => {
    f.status = "uploading";
    f.message = "上传中...";
    // 上传图片要formData类型
    const formData = new FormData();
    formData.append("multipartFile", f.file);
    // 上传文件接口
    uploadFile(formData).then((response) => {
      const { data, resultCode, resultMessage } = response;
      if (resultCode === 0 && data) {
        f.fileId = data.fileId;
        f.fileName = data.fileName;
        f.fileType = data.fileType;
        f.fileUrl = data.fileUrl;
        f.status = "done";
        f.message = "上传完成";
        resolve(f);
      } else {
        f.status = "failed";
        f.message = "上传失败";
        reject(resultMessage);
      }
    }).catch(err => {
      f.status = "failed";
      f.message = "上传失败";
      reject(err)
    });
  })
},

上面代码的执行顺序是,先执行 for 循环,然后直接执行了 Promise.all(),最后执行 promiseList.push();因为 forPromise.all()都是同步代码,所以在 Promise.all(promiseList) 执行时,promiseList 其实是一个空数组,所以 then 最终返回的是一个空数组。

我选择的修改方式是将 for 循环放到了 Promise.all() 中,如下:

js 复制代码
afterRead(file) {
  const _this = this;
  this.isFetchDone = 1;
  let promiseList = [];
  if (!Array.isArray(file)) {
    // 单张图片上传
    promiseList = [file];
  } else {
  	// 批量上传
    promiseList = file;
  }
  /** 可以将 promiseList.map 单独封装成一个函数放在这里(优化代码) */
  Promise.all(
    promiseList.map(f => {
      return new Promise((resolve, reject) => {
        // 压缩文件
        new Compressor(f.file, {
          quality: 0.5,
          success(result) {
            // blob格式转换为file格式
            f.file= new File([result], result.name, { type: result.type });
            f.status = "uploading";
            f.message = "上传中...";
            // 上传图片要formData类型
            const formData = new FormData();
            formData.append("multipartFile", f.file);
            // 上传文件接口
            uploadFile(formData).then((response) => {
              const { data, resultCode, resultMessage } = response;
              if (resultCode === 0 && data) {
                f.fileId = data.fileId;
		        f.fileName = data.fileName;
		        f.fileType = data.fileType;
		        f.fileUrl = data.fileUrl;
                f.status = "done";
                f.message = "上传完成";
                resolve(f);
              } else {
                f.status = "failed";
                f.message = "上传失败";
                reject(resultMessage);
              }
            }).catch(err => {
              f.status = "failed";
              f.message = "上传失败";
              reject(err);
            })
          },
          error(err) {
            console.warn(err.message);
          },
        });
      })
    })
  ).then(result => {
    const bool= result.every(file => file.status === 'done');
    if (bool) {
      this.isFetchDone = 0;
    }
  })
},
相关推荐
Deepsleep.20 分钟前
react和vue的区别之一
javascript·vue.js·react.js
突头小恐龙24 分钟前
Chrome devTools - Lighthouse
前端·javascript·chrome
谦谦橘子24 分钟前
手写tiny webpack,理解webpack原理
前端·javascript·webpack
zqlcoding27 分钟前
使用el-table表格动态渲染表头数据之后,导致设置fixed的列渲染出现问题
前端·javascript·vue.js
海底火旺27 分钟前
破解二维矩阵搜索难题:从暴力到最优的算法之旅
javascript·算法·面试
爱吃的强哥38 分钟前
vue3 使用 vite 管理多个项目,实现各子项目独立运行,独立打包
前端·javascript·vue.js
涵信1 小时前
第十节:性能优化高频题-虚拟DOM与Diff算法优化
javascript·vue.js·性能优化
拖孩1 小时前
【Nova UI】十一、组件库中 Icon 组件的测试、使用与全局注册全攻略
前端·javascript·vue.js·ui·sass
天天扭码2 小时前
深入解析 JavaScript 中的每一类函数:从语法到对比,全面掌握适用场景
前端·javascript·面试
北上ing3 小时前
同一页面下动态加载内容的两种方式:AJAX与iframe
前端·javascript·ajax