循环异步调取接口使用数组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();因为 for 和 Promise.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;
    }
  })
},
相关推荐
麦麦麦当劳大王11 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript
只睡四小时12 小时前
Three.js Sub-tick:漏判 60.7%→0
开发语言·javascript·性能优化·ecmascript·游戏开发·three.js·碰撞检测
excel13 小时前
基于 GPT 的自动发布文章接口方案:从一句话或一张图片生成并发布内容
前端·javascript·后端
OpsEye18 小时前
大模型 Token 计量不准,是什么原因,怎么解决??
javascript·ai编程
独隅20 小时前
WebStorm Windows 版 React / Next.js 实战替换指南
javascript·windows·webstorm
冷眸_20 小时前
同名食材不能直接相减:一个 JavaScript 用量模型的边界
javascript
apollo_qwe20 小时前
接口超时了,前端为什么不能直接重试?
javascript·http
toooooop81 天前
CRMEB 故障排查笔记:安全网关只放行 GET/POST 怎么办
前端·javascript·vue.js·thinkphp6·crmeb
软件技术NINI1 天前
基于SpringBoot和Vue的项目评审系统
javascript·vue.js·spring boot·后端·spring·毕业设计·毕设
vipxieliang1 天前
JavaScript 模板字符串与标签模板:不只是拼接
前端·javascript