fetch 流式下载大文件进度条的核心是利用 response.body 的 readablestream 分块读取,结合 content-length 或 chunked 编码动态计算进度,边读边写避免内存溢出,并妥善处理错误与流关闭。

Fetch 读取 Response.body 实现流式大文件下载进度条,核心是利用 ReadableStream 的分块读取能力,配合 Content-Length 头或 Transfer-Encoding: chunked 动态计算进度,避免一次性加载整个响应体到内存。
获取可读流并逐块读取
Fetch 返回的 Response 对象自带 body 属性,它是一个 ReadableStream。需用 getReader() 获取流读取器,再循环调用 reader.read() 拿到 { done, value } 结构的 chunk(Uint8Array):
- 必须在
response.body.getReader()后立即处理,不能先用.json()或.text()等方法消费流 -
value是二进制数据块,可直接写入Blob、FileWriter或WritableStream(如通过new WritableStream()接收) - 每次
read()返回 Promise,需用await或链式.then()处理
计算下载进度的两种方式
进度计算取决于服务端是否提供明确大小:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 若响应头含
Content-Length(常见于静态文件),可用response.headers.get('content-length')获取总字节数,累加已读chunk.length即得当前进度 - 若服务端用分块传输(
Transfer-Encoding: chunked,如某些代理或动态生成文件),Content-Length不可用,此时只能显示“已接收 X 字节”,无法算百分比;也可结合response.headers.has('content-length')判断是否启用百分比模式
写入文件并更新进度条
为避免内存暴涨,不建议把所有 chunk 拼成一个大 Uint8Array 再构造 Blob。推荐边读边写:
- 创建空
Blob并用URL.createObjectURL()生成临时链接供下载(适合中小文件) - 对超大文件,可用
FileSystemAccess API(Chrome/Firefox 支持)直接写入用户选择的本地文件,或使用Streams API的WritableStream+FileSink - 每次成功读取一个 chunk 后,更新 DOM 中的进度条宽度和文本,例如:
progressBar.style.width = `${(loaded / total * 100).toFixed(1)}%`
错误处理与流关闭
流读取过程可能因网络中断、取消请求或解析失败而终止,需妥善处理:
- 用
try/catch包裹reader.read(),捕获TypeError(如网络错误)或AbortError(请求被取消) - 读取完成后调用
reader.close(),确保流资源释放;即使出错也应调用reader.cancel()清理 - 监听
AbortController.signal可主动中止下载,触发流自动关闭
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










