需求:
- 上传文件,但是后端接口不支持多文件上传,但是一次性发出很多请求的话如果有100个文件那对后端的压力又太大了
- 在上传的时候还需要有停止上传的按钮
进程:文章来源:https://www.uudwc.com/A/9dj6W/
- async await 只能做到第一步,但是无法在上传中的时候关闭这个进程,只能先隐藏进程然后等当前进程结束之后在代码下面加一个判定是不是已经关闭
const uploadFile = async () => {
isCancel.current = false;
for (let i = 0; i < fileList.length; i++) {
if (isCancel.current) {
return;
}
const file = fileList[i]
const res = await uploadFiles({ file })
if (isCancel.current) {
break;
}
}
- 但是这种做法只有在等 uploadFiles 里所有的东西都结束之后才能判定下一步的isCancel,但是这样会有一个问题,就是如果uploadFiles 执行时间很长,那么要么cancel 的执行时间会很长,要么就提前隐藏上传界面,但是这样有风险,如果用的人在cancel 的时候又点击了一下上传,那么就完了, 这个方法里的isCancel 又会变成 false,然后继续执行
- 使用传统的 Promise 中的reject 方法可以随时停止这个异步行为
const createCanCancelRequest = (requestFunc: () => Promise<any>) => {
let func = () => {}
const promise = new Promise((resolve, reject) => {
func = () => reject("上传停止");
requestFunc().then(resolve).catch(reject)
})
return { cancel: func, promise }
}
- 这个方法接收一个传入的匿名函数,然后将匿名函数包裹在 Promise 里,执行并返回一个cancel 方法
- 这个cancel 就是Promise 的 reject 方法,在调用这个方法之后未执行部分就会停止执行
- 但是这个方法有个缺点就是要自己手动写一个sleep,在上一步执行完成之前,都不能停止sleep
const uploadFile = async () => {
isCancel.current = false;
for (let i = 0; i < fileList.length; i++) {
if (isCancel.current) {
return;
}
const file = fileList[i]
isBreak.current = false
const {cancel, promise} = createCanCancelRequest(
() => {
uploadFiles({ file });
isBreak.current = true
}
)
while(1) {
await new Promise(resolve => setTimeout(resolve, 1000));
if (isBreak.current) {
break
}
}
}
拓展:文章来源地址https://www.uudwc.com/A/9dj6W/
- sleep 的逻辑,启动一个setTimeout 这是一个异步的实现,所以可以用 Promise 包起来并且做一个 await 就能实现暂停几秒的逻辑