场景描述:一般情况下直接下载后台压缩好的大文件,通过onDownloadProgress方法可以直接获取该文件的大小以及实时下载的文件进度,实现下载进度条展示;此场景为后端边压缩前端边下载,此时文件总大小未知,不能使用onDownloadProgress方法获取文件总大小及下载进度。
转换思路:后台压缩过程较慢,但压缩之后浏览器下载过程默认可见,所以进度条主要是后台的文件压缩过程。
第一步:通过接口告知后台,前端将对此文件进行下载,后台接收到通知后生成唯一值并开始压缩文件,把唯一值返给前端
第二步:前端收到唯一值,之后通过轮询请求文件压缩过程接口,后台将此文件压缩状态及压缩进度不断返回给前端。
第三步:前端根据状态判断文件是否已经压缩完成,如果压缩完成:后台返回文件地址,前端自动或手动执行下载操作;如果没有完成:前端根据返回的压缩进度绘制进度条;如果报错:重新链接查询。
-
通过pinia封装全局方法组件,以供相通场景快速使用
-
代码逻辑准备,分析可能出现的问题及逻辑场景
可能出现的逻辑场景:
- 当前页面或缓存是否存在压缩任务
- 可以手动终止或开启查询
- 封装查询方法
const polling = async (processId:string, processFn: Function) => {
getProcess(processId).then(process => {
let {status, progressString, totalNum, successNum, failureNum, usedTime, percentComplete} = process.data
if(status == '0'){ // 事件 -- 进行中
if(cancelPolling.value) return
window.setTimeout(() => {
polling(processId, processFn)
}, 500)
return processFn({code: 300, msg: progressString, totalNum, successNum, failureNum, usedTime, percentComplete})
}else if(status == '1'){ // 事件 -- 完成
localStorage.removeItem('layout-processIds')
if(failureNum){
return processFn({code: 400, msg: progressString, totalNum, successNum, failureNum, usedTime, percentComplete})
}else{
return processFn({code: 200, msg: progressString, totalNum, successNum, failureNum, usedTime, percentComplete})
}
}else if(status == '2'){ // 事件 -- 存在异常
localStorage.removeItem('layout-processIds')
return processFn({code: 500, msg: progressString, percentComplete})
}
}).catch(() => {
// 接口异常
if(cancelPolling.value) return
setTimeout(() => {
polling(processId, processFn)
}, 2000)
})
}
- 检查是否存在压缩任务
const checkPolling = async (processFn: Function) => {
let processId = localStorage.getItem("layout-processIds") || ""
if(processId){
cancelPolling.value = false
let res = await polling(processId, processFn)
return res
}else{
return {code: 500, msg: '本地不存在文件任务'}
}
}
- 开启/关闭压缩任务
// 开启压缩任务
const startPolling = async (processId: string, processFn: Function) => {
localStorage.setItem("layout-processIds", processId)
cancelPolling.value = false
let res = await polling(processId, processFn)
return res
}
// 关闭压缩任务
const endPolling = async () => {
cancelPolling.value = true
}