引言:为什么前端需要异步请求?🤔
在 Web 1.0 时代,页面更新全靠刷新 —— 用户点击按钮后,整个页面重新加载,体验像 “翻书” 一样笨重。而 Web 2.0 的核心突破,就是异步请求:让 JavaScript 在不刷新页面的情况下偷偷和后端交互,实现动态更新内容(比如刷朋友圈、加载评论)。
今天我们就来拆解前端异步请求的两大 “功臣”:早期的XMLHttpRequest(简称 XHR)和现代的Fetch API,看看它们如何一步步优化前端数据交互体验!
一、上古神器:XMLHttpRequest 详解 📜
1.1 什么是 XHR?
XMLHttpRequest是浏览器提供的原生 API,诞生于 2005 年左右,是 Ajax(异步 JavaScript 和 XML)技术的核心。它允许前端主动发起 HTTP 请求,彻底改变了 “刷新才更新” 的传统模式。
1.2 实战代码拆解
const getJSON = async (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); // 1. 创建XHR实例
console.log(xhr.readyState); // 输出0:未初始化
xhr.open('GET', 'https://api.github.com/users/shunwuyu/repos'); // 2. 配置请求
console.log(xhr.readyState); // 输出1:已打开连接
xhr.send(); // 3. 发送请求
console.log(xhr.readyState); // 输出1:请求刚发送,未收到响应
// 4. 监听状态变化
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { // 响应完全接收
resolve(JSON.parse(xhr.responseText));
}
}
})
}
1.3 核心知识点:XHR 的生命周期
readyState是 XHR 的灵魂,它的 5 种状态对应请求的完整流程:
-
0:未初始化(刚创建实例,未调用 open)
-
1:已打开(调用 open 后,未发送请求)
-
2:已发送(调用 send 后,未收到响应头)
-
3:接收中(收到部分响应体)
-
4:完成(响应全部接收)
划重点:只有当
readyState === 4时,才能安全地读取responseText!
1.4 如何渲染数据?
通过 IIFE(立即执行函数)包裹异步逻辑,避免顶层await报错:
(async () => {
const data = await getJSON(); // 等待请求完成
// 动态生成列表
document.getElementById('repos').innerHTML =
data.map(item => `<li>${item.name}</li>`).join('');
})()
二、现代方案:Fetch API 详解 ✨
2.1 Fetch 的诞生:为了解决什么问题?
XHR 的语法繁琐(需要手动监听状态、处理解析),而Fetch API在 ES6 后登场,基于 Promise 设计,配合async/await让异步代码像同步代码一样直观!
2.2 实战代码拆解
document.addEventListener('DOMContentLoaded', async () => {
// 1. 发起请求(返回Promise)
const result = await fetch('https://api.github.com/users/shunwuyu/repos');
// 2. 解析响应(response.json()也是异步操作)
const data = await result.json();
// 3. 渲染数据
document.getElementById('repos').innerHTML =
data.map(item => `<li>${item.name}</li>`).join('');
})
2.3 核心知识点:Fetch 的异步链条
-
第一步:
fetch(url)返回一个 Promise,状态为pending -
第二步:当服务器响应时,Promise 变为
fulfilled,得到Response对象(result) -
第三步:
result.json()将响应体解析为 JSON,这也是一个 Promise,需再次await
注意:Fetch 只在网络错误时 reject,HTTP 404/500 等状态不会触发 reject,需手动判断:
if (!result.ok) throw new Error('请求失败');
三、XHR vs Fetch:全方位对比 🔍
| 特性 | XMLHttpRequest | Fetch API |
|---|---|---|
| 语法 | 回调地狱风险(需嵌套事件) | 支持 Promise 和 async/await,更简洁 |
| 错误处理 | 需监听onerror事件 | 仅网络错误 reject,HTTP 错误需手动处理 |
| 响应解析 | 需手动 JSON.parse (responseText) | 内置 response.json () 方法 |
| 中止请求 | 支持 abort () 方法 | 需配合 AbortController |
| 兼容性 | 所有现代浏览器(包括 IE) | IE 不支持,需 polyfill |
| 数据流处理 | 弱 | 支持 Stream API,可处理大文件 |
四、实战总结:该选哪种方案? 🤷♂️
-
选 XHR:需要兼容 IE,或需精细控制请求中止 / 超时
-
选 Fetch:现代项目,追求简洁语法和 Promise 生态
-
终极方案:使用 Axios 等封装库(基于 XHR 或 Fetch),兼顾易用性和兼容性
从 XHR 的 “步步为营” 到 Fetch 的 “一气呵成”,前端异步请求的进化史,也是开发者体验不断优化的历史。你在项目中更爱用哪种方案?欢迎在评论区交流~ 💬