html文件上传需手动计算网速:用xmlhttprequest.upload.onprogress捕获进度,每500ms记录时间与已传字节数,维护3次快照滑动窗口,取首尾差值算平滑瞬时速率(b/s)。

HTML 文件上传本身不提供网速实时波动提示能力,必须靠前端手动计算并渲染——核心是利用 XMLHttpRequest 或 fetch 的进度事件 + 时间窗口内字节数变化率估算瞬时速率。
用 XMLHttpRequest.upload.onprogress 捕获原始上传流
这是最直接、兼容性最好的方式。现代浏览器(包括 Edge 12+)都支持该事件,它在每次底层 TCP 数据包确认后触发,频率高、延迟低。
- 必须显式调用
xhr.open('POST', url, true),true表示异步,否则无法绑定onprogress -
event.loaded是已上传字节数,event.total是文件总大小(仅当服务端返回Content-Length或使用multipart且客户端已知总长时才可靠) - 不要依赖
event.lengthComputable为true——某些代理或 CDN 会剥离Content-Length,此时total为 0,只能靠客户端预存文件大小
每 500ms 计算一次“瞬时速率”,避免抖动误判
单纯用 (loaded - prevLoaded) / (now - prevTime) 会因网络突发/重传导致数值跳变严重。真实场景需加滑动时间窗平滑。
- 维护一个长度为 3 的数组记录最近三次
{ time: number, loaded: number }快照 - 每次
onprogress触发时:移除最旧快照 → 推入新快照 → 取首尾两个快照差值算速率(单位:B/s) - 若两次快照间隔
- 示例片段:
const speed = Math.round((latest.loaded - earliest.loaded) / (latest.time - earliest.time) * 1000);
显示单位要动态切换,且保留小数位逻辑
用户对 “1.2 MB/s” 和 “1240 KB/s” 的感知差异很大,硬写死单位会误导。同时,小数位不是越多越好。
- 速率 X B/s,整数位
- 1024–1048575 B/s → 显示
X KB/s,小数位 1 位(如124.3 KB/s) - ≥ 1048576 B/s → 显示
X MB/s,小数位 1 位(如2.7 MB/s) - 避免显示
0.00 MB/s这类无意义精度——它既不代表零速,也不反映真实波动
注意 CORS 和服务端响应头对 total 的影响
如果页面和上传接口跨域,而服务端没返回 Access-Control-Expose-Headers: Content-Length,那么 event.total 永远是 0,前端无法自动获取总大小。
- 此时必须在上传前通过
file.size预存总字节数,并传给进度计算逻辑 - 若服务端做了分片上传,每个分片的
total就是该片大小,而非整个文件,这时不能复用同一套速率逻辑 - 某些 Nginx 配置会默认屏蔽
Content-Length响应头,检查日志中是否出现"Content-Length" header is ignored
真正难的不是算速率,而是让数字“看起来可信”:用户盯着看时,数值得稳中有动,既不能卡死不动,也不能狂闪乱跳。这需要在采样频率、窗口长度、单位切换阈值之间反复调参,而不是套个公式就完事。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











