js XMLHttpRequest请求
别急着把 XMLHttpRequest 扫进历史:那些 Fetch 替你不干的硬骨头,它还在扛
维护老项目或者接手同事的代码时,你大概率会碰到满屏的 new XMLHttpRequest()。很多人第一反应是吐槽:“这都什么年代了,还不换 Fetch?”但如果你真把它扔进回收站,可能在某个需要实时查看上传进度、或者必须精准中断请求的场景里,被现实狠狠教育一遍。XHR 确实老了,但它手里握着几张现代 API 还没来得及完全复制的王牌。
拆开这老伙计的工作机制并不难。核心逻辑就四步:实例化、配置、发送、监听响应。别一上来就扑向业务代码,先把骨架搭稳,后续排错能省下一半时间。
创建实例并锁定异步模式。构造完对象后调用 open(method, url, true),千万别忘了显式传入 true。同步请求会直接冻结浏览器渲染线程,用户点击一次按钮,整个页面就像掉帧一样卡死,这种基础体验漏洞在审核环节根本过不了。
提前设定响应数据类型。根据后端返回的内容,给 xhr.responseType 赋好值。拉纯文本就留空,拿结构化数据填 'json',传图片或压缩包改成 'blob' 或 'arraybuffer'。这步不写对,后续解析永远多走弯路,甚至引发隐晦的乱码或类型错误。
配置完毕,真正让 XHR 脱颖而出的地方才刚开始。前端做文件上传或大文件下载,光有成功失败两个状态根本不够看。
挂载上传进度监控器。给 xhr.upload 对象绑定 progress 事件,是它最实用的绝活。每次字节传输都会触发回调,通过 event.loaded 除以 event.total 就能算出精确到百分比的进度。Fetch 早期版本原生不支持这功能,虽然现在可以通过流式读取折中实现,但在主流生产环境里,XHR 依然是实现平滑进度反馈的最短路径。
进度条跑得太慢,或者用户中途反悔想取消?网络波动导致请求悬在半空迟迟不返回,这时候就需要动手切断链路。
掌握超时控制与主动中止。在 send() 之前设置 xhr.timeout = 5000,毫秒数一到自动触发 timeout 事件。如果业务允许手动取消,随时调用 xhr.abort() 就能瞬间终止请求,同时触发 abort 回调并重置内部状态。配合统一的全局错误捕获,哪怕跨域拦截或服务器断连,页面也不会因为一个孤儿请求白白消耗内存。
实际敲代码时,几个隐蔽的坑得提前绕开。readyState 只有走到 4 才算真正拿到完整响应,期间 2 和 3 的状态变化常被误用。很多新手把业务逻辑塞进 onreadystatechange 的全生命周期判断里,一旦后端分块返回或多重重定向,代码逻辑就会乱套。更稳妥的做法是只监听 load 事件,用 status 字段校验 HTTP 状态码,避开中间态干扰。
另外,跨域问题从来不是前端单方面的锅。预检请求(OPTIONS)的缓存时长、Vary 头部的设置、甚至请求头里多加了一个自定义字段,都可能触发拦截。遇到 403 或 CORS 报错,先盯着后端的 Access-Control-Allow-Origin 和 Headers 白名单查,比在前端反复折腾代理或包装库管用得多。
技术选型从来不是非黑即白的淘汰赛。Fetch 语法简洁,适合大多数日常交互;XMLHttpRequest 带着厚厚的历史包袱,却在进度追踪、精准控流和复杂表单提交上保留了不可替代的确定性。看懂它的底层状态机,摸清它的边界条件,下次再面对旧代码时,你就能挑出该优化的节点,而不是盲目地重写或硬抗。工具的价值不在于新旧,而在于你知不知道它在什么场景下最能发力。


还没有评论,来说两句吧...