# el-upload 的 before-upload 绑定函数 内部使用异步语句的问题
业务文件位置: 信息流广告平台项目\src\components\SingleFileUpload\index.vue
问题描述: before-upload 绑定函数使用---在重复文件检测条件满足时,pass_vaild 也变为 false 的情况下,还是调用了下一步的 http-request 函数
出问题的业务代码
async onBeforeUpload(file) {
let pass_valid = true;
const { size } = file;
if (size > this.fileSizeLimit) {
this.$message.error(
`上传${TYPE_MAPPER[this.uploadType]}大小不能超过 ${
this.uploadFileSizeLimit
}MB!`
);
pass_valid = false;
}
if (!pass_valid) return pass_valid; // 如果已经确定不通过,则直接返回
// 重复文件检测
if (this.uploadFileAmountLimit > 1 && this.list.length) {
let exist_file_md5s = this.list.map((file) => file.md5);
const cur_file_md5 = await promisefyMd5(file);
if (exist_file_md5s.includes(cur_file_md5)) {
this.$message.warning("请勿重复上传相同文件!");
pass_valid = false;
}
}
console.log(`[Dev_Log][${"pass_vaild"}_]_>>>`, pass_valid);
return pass_valid;
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# el-upload 源码位置 解读
element-ui\packages\upload\src\upload.vue 或者编译文件 element-ui\lib\element-ui.common.js // 29523 行
// 84 行
upload(rawFile) {
this.$refs.input.value = null;
if (!this.beforeUpload) {
return this.post(rawFile);
}
// 执行上传前处理函数得到返回结果
const before = this.beforeUpload(rawFile);
// 上传前处理函数为异步函数,返回promise
if (before && before.then) {
// promise((rs,rj)=>{
//...
// }).then(onFulfilled, onRejected) // then 接送两个回调函数,已完成回调,已拒绝回调
before.then(function (processedFile) { // 已完成回调
var fileType = Object.prototype.toString.call(processedFile);
if (fileType === '[object File]' || fileType === '[object Blob]') {
// ... 其他文件处理
_this2.post(processedFile);
} else {
_this2.post(rawFile);
}
}, function () { // 已拒绝回调
_this2.onRemove(null, rawFile);
});
}
// 上传前处理函数为同步函数,返回Booolean值
else if (before !== false) {
this.post(rawFile);
} else {
this.onRemove(null, rawFile);
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 原因分析
使用 aynsc 绑定的 onBeforeUpload 函数,会走
if (before && before.then)
,再看 before.then(onFulfilled, onRejected), 因为 async onBeforeUpload 函数中没有抛错逻辑,固定就会走 onFulfilled 默认就会上传了,而不是走onRejected 取消上传
# 案列测试
- 不做抛错处理
let aaasF = async function handleFun(){
await Promise.resolve()
}
// // dev-log >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
console.log(`[Dev_Log][${'aaasF'}_]_>>>`, aaasF())
// 输出如下
// [Dev_Log][aaasF_]_>>> Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: null
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 使用throw抛错处理
let aaasF = async function handleFun(){
await Promise.resolve()
throw null;
}
// // dev-log >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
console.log(`[Dev_Log][${'aaasF'}_]_>>>`, aaasF())
// 输出如下
// [Dev_Log][aaasF_]_>>> Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "rejected"
// [[PromiseResult]]: null
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 结合 源码来看 before-upload 可接受异步函数的返回, 若为上诉 async/await 却没有throw报错 直接就满足了before-upload的then(resolve,reject) resolve执行
# 解决方案
# 一:保持 async/await, 但是不满足就直接throw 抛错
- 加 throw
async onBeforeUpload(file) {
let pass_valid = true;
const { size } = file;
if (size > this.fileSizeLimit) {
this.$message.error(
`上传${TYPE_MAPPER[this.uploadType]}大小不能超过 ${
this.uploadFileSizeLimit
}MB!`
);
pass_valid = false;
}
if (!pass_valid) return pass_valid; // 如果已经确定不通过,则直接返回
// 重复文件检测
if (this.uploadFileAmountLimit > 1 && this.list.length) {
let exist_file_md5s = this.list.map((file) => file.md5);
const cur_file_md5 = await promisefyMd5(file);
if (exist_file_md5s.includes(cur_file_md5)) {
this.$message.warning("请勿重复上传相同文件!");
pass_valid = false;
throw null; // before-upload 可接受异步函数的返回,中断上传必须 throw
}
}
return pass_valid;
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 二:使用异步的链式调用
/**
* new_version
* el-upload before-upload 可接受异步函数的返回 用 resolve && reject
*/
onBeforeUpload(file) {
return new Promise(async (resolve, reject) => {
try {
let { size } = file;
if (size > this.fileSizeLimit) {
// prettier-ignore
this.$message.error(`上传${TYPE_MAPPER[this.uploadType]}大小不能超过 ${this.uploadFileSizeLimit}MB!`);
reject(false);
}
/** 重复文件检测 */
// 若上传数量大于 1 && // 若已有上传文件(成功上传的文件都有 MD5 值)
if (this.uploadFileAmountLimit > 1 && this.list.length) {
let exist_file_md5s = this.list.map((file) => file.md5);
// 当前文件MD5获取
let cur_file_md5 = await promisefyMd5(file);
if (exist_file_md5s.includes(cur_file_md5)) {
this.$message.warning("请勿重复上传相同文件!");
reject(false);
}
}
resolve(true);
} catch (error) {
reject(false);
throw error;
}
});
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
或者