👋 前言:前端小白第一次“联网”的惊吓与成长
当我刚学 JavaScript 的时候,觉得网页就该“静静地美丽着”,没想到还有“和服务器说话”这种操作。
直到有一天,我点开了 Chrome 的 DevTools,刷新页面的一瞬间,看着 Network 面板蹦出一堆请求,我意识到:“原来浏览器一直在背地里‘密谋’着什么!”
于是,我开始探索:JS 是怎么跟服务器唠嗑的?
结果发现了两位老少搭档:
🧓 XMLHttpRequest:江湖人称 XHR,AJAX 之父,兢兢业业 20 年
🧒 Fetch:前端新时代的语法颜值担当,Promise 加持
今天,就让我带你从 XHR 一路走向 Fetch,了解它们之间的血泪史与技术交接。
📦 第一代通信工具:XMLHttpRequest(XHR)
🔧 基本用法(经典五步法)
const xhr = new XMLHttpRequest(); // 1. 创建对象
xhr.open('GET', 'https://api.example.com/data', true); // 2. 初始化请求
xhr.onreadystatechange = function () { // 3. 注册事件监听
if (xhr.readyState === 4 && xhr.status === 200) { // 4. 判断状态
console.log(xhr.responseText); // 5. 处理响应数据
}
};
xhr.send(); // 发出请求
这段代码就像一部微型宫廷剧,从发话(open)到办事(send),再到回信(readyState),你得处处小心才能得数据。
📊 readyState 状态码
| 状态码 | 含义 |
|---|---|
| 0 | 请求未初始化 |
| 1 | 请求已建立 |
| 2 | 请求已发送 |
| 3 | 请求处理中(部分数据) |
| 4 | 请求已完成,响应就绪 |
我们只关心 readyState === 4 && status === 200 的高光时刻。
🧪 POST 请求的写法
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/user', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send(JSON.stringify({
name: '前端小白',
age: 18
}));
XHR 就是这样,“多事多虑”,你必须手动设置 header、判断状态、解析响应……有种“旧时代手工艺人”的味道。
🚀 第二代新宠:Fetch API —— Promise 驱动的优雅新世界
🧼 最简洁的 GET 写法
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('出错了:', error));
你没看错,就是这么简单。没有了 readyState、onreadystatechange,返回的是 Promise,优雅得像一篇英文诗。
🧃POST 请求的写法
fetch('https://api.example.com/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: '掘金学徒',
age: 20
})
})
.then(res => {
if (!res.ok) throw new Error('服务器崩了!');
return res.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
Fetch 更加语义化,处理错误也更清晰。你只需专注于“我要什么”,而不是“怎么获取”。
🥊 XHR VS Fetch:来一场公平对决!
| 功能点 | XMLHttpRequest | Fetch |
|---|---|---|
| 语法简洁 | ❌ 多回调 + 状态判断 | ✅ Promise 链式风格 |
| 默认支持 Promise | ❌ | ✅ |
| 错误处理 | ❌ 需要多层嵌套判断 | ✅ 可用 .catch() 捕获 |
| 支持取消请求 | ❌ 不支持 | ✅ 支持 AbortController |
| 自动处理 JSON | ❌ 手动解析 | ✅ 自带 .json() 方法 |
| 跨域带 cookie | ❌ 需要复杂设置 | ✅ credentials: 'include' |
| 兼容性 | ✅ 支持 IE 等古董浏览器 | ❌ IE 不支持 |
📢 总结一句话:XHR 是“手动档”,Fetch 是“自动挡”。
Fetch 写起来轻松,但也不能抛弃 XHR,因为它仍在很多老项目中坚守岗位。
🧰 小工具:封装一个简单的 fetch 请求器
如果你想自己动手封装一个 fetch 工具,下面是个超基础版本:
function request(url, options = {}) {
return fetch(url, {
method: options.method || 'GET',
headers: {
'Content-Type': 'application/json',
...(options.headers || {})
},
body: options.body ? JSON.stringify(options.body) : null
})
.then(res => {
if (!res.ok) throw new Error(res.statusText);
return res.json();
});
}
使用方法:
request('https://api.example.com/data')
.then(data => console.log(data))
.catch(err => console.error(err));
更进一步,你可以引入 try...catch + async/await 写法,像这样:
async function getData() {
try {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error('网络不稳定');
const data = await res.json();
console.log(data);
} catch (err) {
console.error('请求失败:', err);
}
}
🧠 面试官可能问的问题
-
XHR 和 Fetch 的区别?
- 回调 vs Promise
- 状态判断复杂 vs 简洁
- 错误处理 vs 明确抛错
-
fetch 为什么不能直接取消请求?
-
需要借助
AbortController:const controller = new AbortController(); fetch(url, { signal: controller.signal }); controller.abort(); // 中止请求
-
-
fetch 默认不带 cookie 怎么解决?
- 设置
credentials: 'include'
- 设置
📌 总结:从 XHR 到 Fetch,别只是抄 API,要理解通信的本质!
✅ XHR 是网络通信的老牌工具,适合理解底层原理
✅ Fetch 是现代前端的标配,配合 async/await 简直爽飞
✅ 理解状态码、异步处理、错误捕获,是面试和项目的必备技能
✅ 不管你用啥工具,请永远记得:网络通信 = 发请求 + 等响应 + 处理异常
💬 最后一口鸡汤:技术不是堆 API,是对“流程”的掌控
XHR 是老师,Fetch 是朋友。
学会了它们,你就不再是那个只会 alert('你好') 的 JS 小白了。
未来你还会遇到 Axios、GraphQL、WebSocket……
但你得先迈过这第一步,才能走进前端通信的“高级殿堂”。
如果你觉得这篇文章帮你打开了 JS 的“网络之眼”,欢迎点赞、评论、收藏~
如果你还想看我写“从 Fetch 到 Axios 的三国演义”,评论区见!