JavaScript实现文件下载进度条的核心是使用XMLHttpRequest(支持onprogress事件)或fetch+ReadableStream,需服务端返回Content-Length响应头,通过event.loaded/event.total计算百分比并实时更新UI。

JavaScript 中用 Ajax 实现文件下载并显示进度条,核心是使用 XMLHttpRequest(支持 onprogress 事件)或 fetch + ReadableStream(现代方案,但需手动解析进度),而不能用简单的 axios.get 或 fetch 直接触发浏览器下载(它们不暴露底层传输过程)。关键在于:**流式接收二进制数据 + 实时计算已接收字节数 / 总字节数**。
用 XMLHttpRequest 实现带进度的文件下载
这是最直接、兼容性好、能精确监听进度的方式。服务端需返回正确的 Content-Length 响应头,否则无法知道总大小。
- 创建
XMLHttpRequest实例,设置responseType = 'blob' - 监听
onprogress事件:从event.loaded和event.total计算百分比 - 监听
onload:收到完整响应后,用URL.createObjectURL创建临时链接并触发下载 - 注意:必须在
open()后、send()前设置onprogress,且不能用async: false
示例代码:
function downloadWithProgress(url, filename) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
<p>xhr.onprogress = function (e) {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
document.getElementById('progress-bar').style.width = percent + '%';
document.getElementById('progress-text').textContent = <code>${percent}%</code>;
}
};</p><p>xhr.onload = function () {
if (xhr.status === 200) {
const blob = new Blob([xhr.response], { type: xhr.getResponseHeader('content-type') });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename || 'download';
link.click();
URL.revokeObjectURL(link.href);
}
};</p><p>xhr.onerror = function () {
alert('下载失败');
};</p><p>xhr.send();
}用 fetch + ReadableStream 模拟进度(现代浏览器)
原生 fetch 不提供上传/下载进度事件,但可通过 ReadableStream.getReader() 分块读取响应体,结合 Content-Length 手动累计已读字节数来模拟进度。
立即学习“Java免费学习笔记(深入)”;
- 先发一次
HEAD请求获取Content-Length(或从Response.headers中读取,前提是服务端允许 CORS 暴露该 header) - 再用
GET获取流,用reader.read()循环读取Uint8Array块 - 每读一块就更新进度:当前累计字节数 ÷ 总字节数
- 最后将所有块合并为
Blob并下载
⚠️ 注意:此方法在 Safari 等浏览器中对大文件可能有内存压力,且 Content-Length 在跨域时需服务端显式设置 Access-Control-Expose-Headers: Content-Length。
后端配合要点(不可忽略)
前端进度条能否准确显示,高度依赖服务端响应头配置:
- 必须返回
Content-Length(静态文件通常自动包含;动态生成如 Node.js/Express 需确保未启用 chunked transfer encoding) - 跨域场景下,服务端需设置
Access-Control-Expose-Headers: Content-Length - 推荐设置
Content-Disposition: attachment; filename="xxx.pdf",便于前端默认提取文件名 - 避免使用重定向(302),因为
XMLHttpRequest的onprogress在重定向后不会继续触发
常见问题与绕过限制的技巧
有些场景无法获取 Content-Length(如流式生成、代理转发、gzip 压缩未解压),此时只能显示「不确定进度」的动画(如旋转加载图标 + 已下载字节数):
- 监听
onprogress时若!e.lengthComputable,可显示已接收 ${e.loaded} 字节… - 对于必须用
axios的项目,可用axios.get(url, { responseType: 'blob', onDownloadProgress: e => {...} }),它内部封装了XMLHttpRequest - 不要尝试用
iframe或<a download>实现进度——它们完全不暴露下载过程
本质上,进度条不是“下载功能”的附加项,而是对底层网络传输状态的可视化反馈。只要抓住“可计算总量 + 可监听增量”这个前提,方案就很清晰。


















