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

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

我使用 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;
    }
  })
},
相关推荐
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
燃先生._.8 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖9 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
black^sugar10 小时前
纯前端实现更新检测
开发语言·前端·javascript
2401_8576009511 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_8576009511 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL11 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据11 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_8575834911 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js