Fetch API 在现代项目中优于 XMLHttpRequest,因其原生 Promise、async/await 支持、自动 JSON 解析、集中配置及无全局状态;但 IE11 兼容和上传进度监控仍需 XMLHttpRequest。

Fetch API 在绝大多数现代项目中已优于传统 AJAX(XMLHttpRequest),尤其在可读性、维护性和异步控制上优势明显;但若需支持 IE11 或精细控制上传进度,XMLHttpRequest 仍不可替代。
为什么 fetch() 写起来更顺手?
它原生返回 Promise,天然适配 async/await,不用再嵌套 onreadystatechange 和手动判断 xhr.readyState === 4。错误处理也更直接:网络失败会 reject,而 HTTP 错误(如 404、500)则需要检查 response.ok —— 这看似多一步,实则避免了传统 AJAX 中“请求发出去了但 status 是 0”这类模糊状态。
-
fetch()自动解析 JSON:调用response.json()即可,不用再写JSON.parse(xhr.responseText) - 请求配置统一收在第二个参数对象里,比如
{ method: 'POST', headers: {}, body: JSON.stringify(data) },比xhr.setRequestHeader()+xhr.send()更集中 - 没有全局状态,不会因多个请求共用一个
xhr实例而互相干扰
什么时候还必须用 XMLHttpRequest?
两个硬性场景目前无法被 fetch() 完全覆盖:
-
上传进度监控:
xhr.upload.onprogress能实时拿到event.loaded和event.total,fetch()没有等效机制(ReadableStream可读但不暴露上传进度) -
IE11 兼容需求:哪怕加了 polyfill,某些 header(如
Authorization带空格)或重定向行为仍可能出偏差;企业内网老系统若明确要求支持 IE11,XMLHttpRequest 仍是稳妥选择
fetch() 的坑:常见报错与绕过方式
新手最常卡在三类问题上:
-
TypeError: Failed to fetch:通常是网络中断、CORS 被拒,或请求地址协议不匹配(如http://页面请求https://接口),不是服务端返回 500 导致的 -
response.json() 报 Unexpected end of JSON input:说明后端返回了非 JSON 内容(比如 HTML 错误页),务必先检查response.headers.get('content-type')是否含application/json - 超时控制要靠
AbortController:原生fetch()不支持timeout参数,必须手动:const controller = new AbortController();
setTimeout(() => controller.abort(), 8000);
fetch('/api/data', { signal: controller.signal })
性能差异真有那么大?
实测数据(100 次平均)显示:小数据量(fetch() 更少的中间层封装和更高效的流式响应处理能力。但真实项目中,这点差异通常被网络延迟掩盖 —— 真正影响体验的是你是否用了 keep-alive、是否压缩了响应、是否合理设置了缓存头。
真正容易被忽略的是:fetch 的 cache、redirect、credentials 等选项默认值和 XMLHttpRequest 不同,比如 fetch() 默认不带 cookie(credentials: 'include' 才等价于 xhr.withCredentials = true),漏设会导致登录态丢失。










