上传进度条没反应的根本原因是监听对象错误或时机不当:必须将onprogress绑定到xhr.upload而非xhr本身,且须在xhr.open()后、xhr.send()前设置;fetch不支持原生上传进度监听。

上传进度条为什么没反应?检查 XMLHttpRequest 的事件监听顺序
进度条不更新,大概率是事件监听写在了 send() 之后,或者漏掉了 upload 属性上的监听。原生 XMLHttpRequest 的上传事件(如 progress)必须绑定在 xhr.upload 对象上,而不是 xhr 本身。
正确做法:
- 先创建
XMLHttpRequest实例 - 立即给
xhr.upload.onprogress赋值回调函数 - 再调用
xhr.open()和xhr.send()
示例关键片段:
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
document.getElementById('progress').value = percent;
}
};
xhr.open('POST', '/upload');
xhr.send(formData); // 必须在监听后调用
用 fetch 能监听上传进度吗?不能直接监听,但可以封装流式上传
fetch 本身不提供上传进度事件,因为它的设计是基于 Promise + 流(ReadableStream),没有内置的 onprogress。想用 fetch 实现进度反馈,得手动分块读取 File 并逐块发送,同时计算已发比例。
立即学习“前端免费学习笔记(深入)”;
适用场景:需要兼容现代浏览器、且上传大文件时希望更精细控制(比如断点续传前奏)。
注意点:
- 每次
fetch发送的是一个分块,需服务端配合接收分块并合并 - 浏览器对
ReadableStream的getReader()支持良好,但stream.pipeTo()在某些旧版 Edge 中不可靠 - 简单上传小文件,不如直接用
XMLHttpRequest省事
input[type="file"] 多文件上传时,如何分别显示每个文件的状态?
不能只依赖单个 progress 事件——它反映的是整个请求体的上传进度,而多文件通常打包进一个 FormData,服务端也常统一处理。要实现“每个文件单独进度”,必须为每个文件发起独立请求。
实操建议:
- 遍历
input.files,对每个File创建独立的XMLHttpRequest - 用闭包或
data-*属性把当前文件名/索引绑定到对应进度条 DOM 元素上 - 避免并发过多导致浏览器限流(Chrome 默认约6个同域并发),可加简单队列控制(如每次最多3个并发)
例如,为第 i 个文件设置进度条:document.querySelector(`#progress-${i}`).value = percent;
上传完成但页面没更新?别忘了处理 load 和 error 的边界情况
只监听 progress 不够,上传结束状态必须靠 xhr.onload 或 xhr.onerror 触发 UI 更新。常见疏漏是:成功后没隐藏加载态、失败后没提示错误原因、网络中断时 onerror 没触发但 ontimeout 也没设。
务必补充:
-
xhr.timeout = 30000;并监听ontimeout -
xhr.onload中检查xhr.status是否为 200–299 -
xhr.onerror里不要只写console.error,至少更新 UI 显示“上传失败,请重试”
特别注意:如果服务端返回非 JSON 内容(比如 HTML 错误页),JSON.parse(xhr.response) 会抛错,应先判断 xhr.getResponseHeader('content-type')?.includes('json')。



















