HTML原生不支持直接获取上传速度,需用XMLHttpRequest.upload.progress事件结合时间戳手动计算;文件夹上传依赖webkitdirectory或directory属性,但兼容性差,且需JS主动发起请求才能测速。

HTML 原生不支持直接获取上传速度(即字节/秒),但可以通过 XMLHttpRequest.upload 的 progress 事件 + 时间戳差值手动计算。文件夹上传本身依赖浏览器对 webkitdirectory 和 directory 的支持,不是所有浏览器都可用。
为什么不能直接用 input type="file" 获取上传速度
浏览器的 FileList 对象只提供文件元信息(name、size、webkitRelativePath),不暴露传输层状态。上传动作必须由 JS 主动发起(如 fetch 或 XMLHttpRequest),才能监听进度并推算速度。
-
input元素本身触发的表单提交是黑盒行为,无法拦截或测量实时速率 - 即使设置了
enctype="multipart/form-data",原生提交也不触发progress事件 - 真正可测速的前提:用 JS 构造请求、分片或逐个上传文件,并自己维护时间窗口
webkitdirectory 和 directory 的实际兼容性
这两个属性是开启文件夹选择的关键,但行为差异大,且存在隐性限制:
-
webkitdirectory:Chrome、Edge、新版 Safari 支持;选中文件夹后,e.target.files包含所有子文件,每个File对象的webkitRelativePath保留目录结构 -
directory:仅 Firefox 支持;效果类似,但路径字段叫relativePath(非标准,部分版本可能为空) - IE、旧版 Safari、多数国产浏览器(如 360 极速模式)完全不识别这两个属性,会退化为单文件选择
- 移动端(iOS Safari、Android Chrome)基本不支持文件夹选择,
multiple也常被忽略
如何在上传过程中估算实时速度
核心思路:记录每次 progress 事件的时间与已上传字节数,用滑动窗口计算最近 N 次的平均速率。不要只用单次增量除以单次时间差——网络抖动会导致结果跳变。
- 在
xhr.upload.onprogress中缓存{ time: Date.now(), loaded: e.loaded }到数组 - 只保留最近 3–5 条记录(避免内存累积),剔除超过 2 秒的旧条目
- 速率 =
(latest.loaded - earliest.loaded) / (latest.time - earliest.time)(单位:bytes/ms → ×1000 得 bytes/s) - 注意:总大小
e.total在分片上传时不可靠(后端可能不返回Content-Length),建议用file.size预估 - 示例片段:
let speedSamples = []; xhr.upload.onprogress = function(e) { const now = Date.now(); speedSamples.push({ time: now, loaded: e.loaded }); // 清理超时样本 speedSamples = speedSamples.filter(s => now - s.time = 2) { const first = speedSamples[0]; const last = speedSamples[speedSamples.length - 1]; const speedBps = Math.round((last.loaded - first.loaded) / ((last.time - first.time) / 1000)); console.log(speedBps + ' B/s'); } };
文件夹上传时容易被忽略的细节
机械制造等场景下,文件夹常含大量小文件(如 BOM 表格、STEP 模型缩略图),这些细节直接影响上传稳定性和用户体验:
- macOS 用户拖入文件夹时,
__MACOSX隐藏目录会混入FileList,需过滤:file.webkitRelativePath.includes('__MACOSX') - Firefox 下
relativePath可能为null,得 fallback 到文件名拼接,否则目录结构丢失 - 单次上传 50+ 文件时,浏览器并发连接数有限(通常 6 个),盲目
for...of发起请求会阻塞,应加队列控制(如 Promise.allSettled + 并发数限流) - 后端接收时,若用
multer(Node.js)或request.FILES(Django),默认不解析嵌套路径,需手动按webkitRelativePath构建服务端存储路径
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











