上传时序问题
问题背景
在使用 ElementPlus 的 Upload 组件进行自定义上传时,存在如下问题:
ts
/**
* 上传与案件相关的资料,返回FileID
* @param option
* @param isChunk 是否使用分片上传
*/
export async function uploadCaseFile(
option: UploadCaseFileOption,
isChunk = false
) {
// 文件大小超过50MB时使用分片上传
if (isChunk && option.file.size > 50 * 1024 * 1024) {
// 1. 分片上传
const url = await uploadChunk(option); // 后端没有存URL
// 2.绑定案件
const fileID = await getFileIdAndBundleCaseByURL({
url,
caseId: option.data.caseId,
type: option.data.type,
fileName: option.file.name,
});
setTimeout(() => {
option.onSuccess(fileID);
}, 0);
} else {
console.log(option);
const { process, source } = uploadNormalCaseFile(option, {
caseId: option.data.caseId,
type: option.data.type,
});
const res = await process;
setTimeout(() => {
option.onSuccess({
...res,
source,
});
}, 0);
}
}如果没有 setTimeout,file.response 将为 undefined
setTimeout(fn, 0)
setTimeout(fn, 0) 的作用是将回调函数 fn 放入事件循环的任务队列中,使其在当前执行栈中的所有同步任务完成后立即执行。
尽管延迟时间为 0 毫秒,但它并不意味着立即执行。这是因为 JavaScript 是单线程的,它需要等待主线程空闲下来才能执行任务队列中的任务。
setTimeout(fn, 0) 的执行机制
- 调用 setTimeout(fn, 0):当调用 setTimeout 时,浏览器会启动一个计时器,并立即将回调函数 fn 放入任务队列(宏任务队列)。
- 执行同步代码:主线程继续执行当前执行栈中的所有同步代码。
- 事件循环:当同步代码执行完毕后,事件循环(Event Loop)开始工作。
- 执行回调函数:事件循环会从任务队列中取出 fn 并将其推入执行栈,从而执行回调函数。
