JS分块下载大文件如何实现带百分比的下载进度显示
分块下载实时进度改造方案
原有实现无进度的核心原因是逻辑上等待所有分片完整返回、拼接成最终Blob后才触发浏览器保存动作,下载过程完全在JS逻辑里静默执行,浏览器无法感知中间状态。要实现和原生下载一致的实时百分比进度,按以下逻辑改造即可:
- 提前统计所有分片的总字节大小:通过响应头的
Content-Length字段拿到每个分片的大小,累加得到完整文件总大小,作为进度计算的基数。 - 流式读取分片响应:不要直接用
res.blob()等待整个分片下载完成,而是通过ReadableStream逐块读取响应数据,每读取到一段数据就累加已下载字节数,实时计算进度百分比。 - 进度同步更新到UI:计算得到的百分比可以直接绑定到自定义的进度条、进度文本组件上,实现实时反馈。
- 所有分片读取完成后,拼接成完整Blob触发文件保存,最后记得释放生成的对象URL避免内存泄漏。
改造后完整代码
async function testDownload() { try{ const urls = ['https://localhost:54373/analyzer/test1','https://localhost:54373/analyzer/test2'] const chunkList = [] let totalFileSize = 0 let loadedSize = 0 // 预取所有分片的总大小 for (const url of urls) { const headResp = await fetch(url, { method: 'HEAD' }) if (!headResp.ok) throw new Error('分片信息获取失败') totalFileSize += Number(headResp.headers.get('Content-Length')) || 0 } // 逐块流式下载,实时更新进度 for (const url of urls) { const resp = await fetch(url) if (!resp.ok || resp.status !== 200) { throw new Error('下载失败'); } const reader = resp.body.getReader() const chunkParts = [] while (true) { const { done, value } = await reader.read() if (done) break chunkParts.push(value) loadedSize += value.length // 计算当前进度,此处替换为你自己的UI更新逻辑 const progress = Math.round((loadedSize / totalFileSize) * 100) console.log(`下载进度:${progress}%`) // 示例:更新页面进度条 document.querySelector('#download-progress').style.width = `${progress}%` } chunkList.push(new Blob(chunkParts)) } // 全部下载完成后触发保存 const fullFile = new Blob(chunkList) const fileUrl = window.URL.createObjectURL(fullFile) const a = document.createElement('a') a.href = fileUrl a.download = "WTF.ini" a.click() // 释放临时URL window.URL.revokeObjectURL(fileUrl) } catch(e){ console.error(e) } }
补充说明:如果你的分片接口不支持HEAD请求,可以去掉单独的HEAD请求步骤,在第一次GET请求拿响应的时候先读取
Content-Length累加总大小,再开始读流,能减少一次网络请求。如果分片大小是固定的,也可以直接用分片数*单分片大小计算总大小,不用额外发请求。
内容的提问来源于stack exchange,提问作者Alex Soryn
相关产品推荐
相关产品推荐

