循环异步调取接口使用数组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;
    }
  })
},
相关推荐
无心使然云中漫步1 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者1 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_2 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋3 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120533 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢3 小时前
【Vue】VueRouter路由
前端·javascript·vue.js
随笔写4 小时前
vue使用关于speak-tss插件的详细介绍
前端·javascript·vue.js
快乐牌刀片885 小时前
web - JavaScript
开发语言·前端·javascript
秋雨凉人心5 小时前
call,apply,bind在实际工作中可以使用的场景
javascript
哪 吒5 小时前
华为OD机试 - 第 K 个字母在原来字符串的索引(Python/JS/C/C++ 2024 E卷 100分)
javascript·python·华为od