在使用 vue + vant@2.13.2
技术栈的项目中,因为上传文件的接口是单文件上传,当使用批量上传时,只能循环调取接口;然后有校验内容:需要所有文件上传成功后才能保存,在文件上传不成功时点击保存按钮,则提示信息:"文件上传未成功!"
。
我使用 for 循环调取接口,然后定义了 promiseList
数组,循环一次将 promise
对象添加一次,然后使用 Promise.all(promiseList).then(result=>console.log(result))
来改变保存的状态。但是发现打印出的 result 总是空数组[]
。debugger 代码的执行顺序,应该是异步的原因导致的。
如下代码:
/** 上传文件组件 */
<van-uploader
name="multipartFile"
multiple
v-model="jobFileList"
:after-read="(file) => afterRead(file, jobFileList)"
:before-read="(file) => beforeRead(file, jobFileList)"
:before-delete="(file) => beforeDelete(file, jobFileList)"
:max-count="9"
>
</van-uploader>
下面上传了一张图片文件格式;如下图,其中 fileId、fileName、fileType、fileUrl
为自定义字段,上传服务器成功后返回的,其他字段为 van-uploader
组件所支持的自有字段。
/** 上传文件逻辑 */
afterRead(file, jobFileList) {
console.log("file", file); // 如上图
const _this = this;
this.isFetchDone = 1; // 文件是否全部上传完成:0是 1否
let promiseList = [];
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, jobFileList);
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, jobFileList) {
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) {
f.status = "done";
f.message = "上传完成";
resolve(data);
} 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() 中,如下:
afterRead(file, jobFileList) {
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 } = response;
if (resultCode === 0 && data) {
f.status = "done";
f.message = "上传完成";
resolve(f);
} else {
f.status = "failed";
f.message = "上传失败";
reject(f);
}
}).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;
}
})
},