从 0 到 1 实现 getJSON 方法:深入理解 XMLHttpRequest 与现代请求方案
亲手实现一个基于XMLHttpRequest的getJSON方法,能帮我们更透彻理解网络请求的底层逻辑。
一、 getJSON
const getJSON = (url) => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const data = JSON.parse(xhr.responseText);
resolve(data);
} catch (err) {
reject(`JSON解析失败:${err.message}`);
}
} else {
reject(`请求失败:状态码${xhr.status}`);
}
}
};
// 监听网络错误(如断网、跨域拦截)
xhr.onerror = () => {
reject('网络请求失败,请检查网络连接');
};
});
getJSON('https://api.github.com/users/shunwuyu')
.then(data => console.log('用户数据:', data))
.catch(err => console.error('请求出错:', err));
二、核心 API 解析
实现getJSON的关键是理解XMLHttpRequest的四个核心成员:
-
readyState表示请求的生命周期状态,共 5 个值:
- 0:未初始化(
open未调用) - 1:已打开(
open已调用,send未调用) - 2:已发送(
send已调用,响应头已接收) - 3:加载中(正在接收响应体)
- 4:完成(响应体完全接收)我们只在
readyState === 4时处理响应,因为此时数据才完整。
- 0:未初始化(
-
onreadystatechange监听
readyState变化的事件回调,每次状态改变都会触发。正因为它会多次触发,所以必须通过readyState === 4过滤无效状态。 -
responseText存储服务器返回的响应体文本,对于 JSON 请求,需要用
JSON.parse转换为 JavaScript 对象。注意这里可能出现解析错误,必须用try/catch捕获。 -
onerror专门处理网络层面的错误(如断网、域名无法解析),这类错误不会触发
onreadystatechange,需要单独监听。
三、与 fetch 的对比
// fetch版本
const fetchJSON = (url) =>
fetch(url)
.then(response => {
if (!response.ok) throw new Error(`状态码${response.status}`);
return response.json();
});
// 使用方式相同
fetchJSON('https://api.github.com/users/shunwuyu')
.then(data => console.log(data))
.catch(err => console.error(err));
四、为什么要学 XMLHttpRequest?
虽然fetch更简洁,但理解XMLHttpRequest有重要意义:
- 掌握底层原理:理解
fetch的设计思路来源 - 兼容旧环境:部分老旧系统仍需支持 IE
- 精细化控制:
XMLHttpRequest提供更细粒度的状态监听(如上传进度) - 问题排查:遇到请求异常时,能从底层分析原因
总结
通过实现getJSON,我们不仅获得了一个实用的工具函数,更深入理解了浏览器网络请求的底层机制。XMLHttpRequest虽然语法相对繁琐,但它的状态管理、错误处理设计,为现代请求 API 提供了重要参考。
在实际开发中,推荐优先使用fetch或成熟库(如 axios),但亲手实现一次getJSON,会让你对网络请求的理解更上一层楼。