最可靠方式是监听 xhr.upload 的 progress 事件;需用 file.slice 分片上传避免内存阻塞;通过时间差与字节差计算瞬时速率,并结合网络信息判断状况;暂停续传需缓存成功分片索引并校验服务端状态。

直接监听 xhr.upload 上的 progress 事件,是监控上传字节流向最可靠的方式。XMLHttpRequest Level 2 明确将上传和下载通道分离,进度信息只在 xhr.upload 对象上触发,不能监听 xhr 本体。
必须绑定到 xhr.upload 而非 xhr
很多上传进度不更新,根源就是写成了 xhr.addEventListener('progress', ...)。这完全无效,因为上传事件不在主 xhr 实例上。
- 正确写法是:
xhr.upload.addEventListener('progress', handler) - handler 中可拿到
event.loaded(已发出字节数)和event.total(总字节数) - 若
event.lengthComputable === false,说明服务端没返回Content-Length,此时event.total为 0,需改用分片序号或累计发送量估算“伪进度”
处理大文件时避免内存阻塞
HTML 编辑器中拖入百兆级 HTML 包,不能用 FileReader.readAsArrayBuffer(file) 一次性读取——会卡 UI 且耗尽内存。
- 应使用
file.slice(start, end)手动切片,推荐 chunkSize = 5MB(即5 * 1024 * 1024) - 注意
slice第二个参数是结束位置(不包含),不是长度;边界要手动判断,防止越界 - 每片请求带上唯一标识,如请求头
X-Upload-Chunk: 3/20,便于服务端校验与续传
计算瞬时上传速度与网络状况
仅看百分比不够,实时速度更能反映网络波动。可在 progress 回调中做时间差与字节差运算。
- 记录每次事件触发的时间戳和
event.loaded - 用前后两次的字节数差 ÷ 时间差,得出瞬时速率(单位:B/s)
- 结合
navigator.connection.effectiveType和downlink,可对比预估带宽,判断当前是否限速或弱网
暂停/续传必须缓存已成功分片状态
用户在编辑 HTML 时点暂停,不能只调 xhr.abort() —— 那样续传时无法知道哪些片已落库。
- 需维护一个已确认上传成功的分片索引集合(如
new Set([0, 1, 2])) - 续传前先发 HEAD 请求校验服务端是否存在该分片,避免重复上传或跳片导致合并失败
- 整体进度建议用加权平均:每片按大小加权,而非简单按片数平均


















