前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库fetch 上传进度 不支持 XHR upload
浏览浏览器请求与通信 API

为什么原生 fetch 无法监听文件上传进度,有哪些替代方案?

原生 fetch 规范没有上传进度事件,所以无法用 fetch 直接监听。可用 XMLHttpRequest 的 upload 上的 progress 事件,或用流式请求体自行计算。

前端进阶之旅 · 一题精讲更新于 2026.09.05
浏览器#请求与通信 API#HTTP#流处理
先看核心答案
理解线索

上传进度的事件支撑

  1. fetch 缺事件规范只定义响应读取
  2. XHR upload专门监听上传进度
  3. 流式计数自定义 TransformStream

浏览器没有原生通用上传进度事件,选型取决于是否需要精确进度。

核心回答

先记住这个答案

fetch() 返回的 Promise 只关心响应,不暴露请求中间状态。规范未规定 Request body 发送时的进度回调。要获取上传进度,应改用 XMLHttpRequest:其 upload 对象会触发 progress 事件,提供 loaded 和 total。另一种思路是用 fetch 上传 ReadableStream 并包装流统计字节,但需要 duplex: 'half' 且无法获得网络层确认,只适合简单模拟。

  • fetch 规范无上传进度事件
  • XHR upload 对象有 progress 事件
  • 流式方案只能近似统计

为什么 fetch 没有上传进度事件

fetch 规范只暴露请求创建和响应读取,并没有为上传阶段定义任何事件回调。规范中的 RequestInit.body 可以是字符串、FormData 或 ReadableStream,但发送过程由 HTTP 层管理,开发者无法订阅每块数据的发送结果。

即便把 body 设为 ReadableStream,fetch 内部会把流作为请求体管道输出,但规范没有规定向上传递发送进度。因此即便流中每个 chunk 被读取,也只能说明数据进入缓冲区,不代表被服务器接收,无法得到可靠百分比。

进度条需求下的技术选型

假设要上传一个 100MB 文件到对象存储,界面需要显示已传百分比。若使用 fetch,浏览器不提供任何事件源,只能靠自造流估算,而该估算与实际网络发送可能偏差较大。此时应改用 XMLHttpRequest,其 upload 对象上有 progress 事件。

实现时 new XMLHttpRequest(),open 对应地址,把 xhr.upload.onprogress 赋值,在该回调里读取 e.loaded 和 e.total,即可计算百分比。XHR 的 progress 事件由浏览器在收到上传数据确认时触发,相对准确,适合对进度有硬性要求的场景。

方案失效与处理

fetch 流式方案依赖 duplex: 'half',Chrome 105 才默认支持,旧浏览器无法使用;且统计的字节只是进入网络栈的量,并非服务端已接收的有效数据,若需精确到服务端收到,必须靠后端返回进度。

XHR 也不是万能:部分环境(如 Service Worker 内)没有 XMLHttpRequest;上传大文件时 progress 事件粒度受浏览器调度影响,可能超过数百毫秒才回调。替代时还需考虑断点续传等需求,必要时用双向流或 WebSocket。

回答前,多想一步

容易答错的地方

fetch 可以通过 response.body 读取到上传进度
response.body 是响应体,与上传无关。上传进度只能在请求阶段获得,fetch 没有提供这类事件。正确做法是使用 XHR upload 事件或让服务端回传进度信息。
ReadableStream 的 enqueue 计数就是上传进度
流读取只代表本地消费,不等于服务器确认。进度应反映网络层发送结果,stream 计数只能估算本地 CPU 处理量,无法替代真实上传进度。
试着用自己的话回答

面试官还会怎么问?

XHR 上传进度事件能取到 total 为 0 时怎么办?

e.lengthComputable 为 false 时无法计算百分比,常见于 chunked 编码。可改用 Content-Length 头或让后端返回任务 ID 以进度接口查询。

fetch 的 duplex: 'half' 有什么限制?

需要同时满足请求体是 ReadableStream 且请求不是 keepalive,必须显式指定这个选项才能发送流,而且无法获取实时上传进度。

Service Worker 中怎么获取上传进度?

Service Worker 中的 fetch 也没有进度事件,但可以使用 Request 的 body 作为流并自行观察字节,仍然不能得到真实网络发送进度,只能靠响应回执。

从一道题,走向一组知识

把知识连起来

请求与通信 API

fetch 默认跨域请求为什么不带 Cookie,credentials 选项各取值有什么区别?

同属「请求与通信 API」专题,接着看 fetch credentials cookie same-origin include 在具体场景中的处理方式。

请求与通信 API

为什么 fetch 收到 HTTP 404 或 500 响应时 Promise 不会 reject,应该怎么处理?

同属「请求与通信 API」专题,接着看 fetch HTTP 错误不 reject 处理 在具体场景中的处理方式。

参考资料

  • Fetch API

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么 fetch 没有上传进度事件
  3. 进度条需求下的技术选型
  4. 方案失效与处理
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑