HTML进度条需手动同步值,无法自动跟踪网络请求等;必须用JS在事件回调中更新progress.value,或对无总长场景使用indeterminate模式;fetch需ReadableStream分块读取并处理content-length,XMLHttpRequest.upload.onprogress更适配上传且兼容性好。

HTML 进度条本身不感知加载状态,必须手动同步值;直接写 <progress></progress> 标签或用 <meter></meter> 都不会自动跟踪网络请求、文件读取或计算过程。
progress 元素的 value 属性必须由 JS 主动更新
浏览器不会自动把 <progress></progress> 和 fetch / XMLHttpRequest / FileReader 等绑定。你得在事件回调里手动设 progress.value:
- 对已知总长的下载(如 Content-Length 可预知),用
event.loaded / event.total计算百分比后赋值 - 对无总长的流式加载(如 chunked response),只能用不确定模式:
progress.removeAttribute('value'),靠indeterminate视觉效果示意进行中 - 别直接操作
progress.innerHTML或试图用 CSS 动画“模拟”进度——这会误导可访问性(AT 工具读不到真实状态)
fetch + progress 事件需要手动启用并监听
原生 fetch 默认不触发 progress 事件,必须用 ReadableStream 分块读取:
const response = await fetch('/big-file.zip');
const reader = response.body.getReader();
let loaded = 0;
const total = response.headers.get('content-length'); // 注意:有些服务器不返回这个
<p>while(true) {
const { done, value } = await reader.read();
if (done) break;
loaded += value.length;
if (total) {
progress.value = (loaded / total) * 100;
}
}</p>
-
response.headers.get('content-length')可能为null,不能假设一定存在 - 服务端需开启 CORS 并显式暴露该 header:
Access-Control-Expose-Headers: content-length - 不要用
response.json()或response.text()—— 它们是一次性读完,无法分段更新进度
表单提交时用 FormData + xhr 更可控
上传文件等场景,XMLHttpRequest 的 upload.onprogress 是最稳定的选择:
-
xhr.upload.onprogress在上传阶段触发,xhr.onprogress是下载阶段(常被忽略) -
FormData支持追加 Blob/File,且兼容老浏览器,比fetch + ReadableStream覆盖面更广 - 注意设置
xhr.upload.onprogress必须在xhr.open()之后、xhr.send()之前 - 移动端 Safari 对
upload.onprogress的触发频率较低,别依赖它做高精度动画
进度条是否“可信”,取决于你有没有把真实数据流转节点和 progress.value 对齐——比如分片上传时,是按分片数算 10%,还是按字节数算?后者更准,但需要服务端配合返回每片实际大小。这点很容易被跳过,结果用户看到进度条卡在 99% 半分钟不动。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











