以为 Ajax 是老古董?2025 年它依然是区分初级和资深前端的试金石
最近刷到不少前端同学的吐槽:"面试被问 Ajax 原理,我答 ' 用 axios 就行啊 ',结果当场凉了..."
其实不怪大家,现在框架封装得太好,Axios、Fetch API 随手就来,谁还会扒开底层看 XMLHttpRequest?但你知道吗?去年某大厂前端面试中,"Ajax 核心逻辑" 的考察频率比前两年上涨了 37%—— 毕竟,能讲清 "为什么要封装" 的人,才是真正懂前端的。
今天咱们就用 "拆盲盒" 的思路,从实际业务痛点出发,把 Ajax 的底层逻辑、现代用法和避坑指南一次性讲透。看完这篇,别说面试,以后看 Axios 源码都像看漫画书。
一、先问个扎心的:没有 Ajax 的年代,网页有多 "笨"?
你肯定见过这种场景:填完一个表单点提交,整个页面瞬间变白,转圈圈转半天,然后唰地一下刷新出结果 —— 这就是 "无 Ajax 时代" 的典型体验。
为什么会这样?因为早期的 HTTP 请求是 "一次性买卖":浏览器发请求,服务器返回完整 HTML,浏览器扔掉旧页面、重新渲染新页面。就像你去餐厅点外卖,必须等厨师做完一整桌菜,才能拿到你单点的那碗面。
而 Ajax(Asynchronous JavaScript and XML)的出现,相当于给浏览器开了个 "悄悄话通道":不用刷新页面,偷偷摸摸和服务器交换数据。就像外卖平台的 "催单功能",不用挂掉电话重拨,直接在 APP 里发个消息就行。
一句话总结:Ajax 的核心不是技术,而是 "异步局部更新" 的思想 —— 这也是现在所有前端交互框架的底层逻辑。
二、扒开 Ajax 的 "三件套":原来就这么简单
很多人觉得 Ajax 高深,其实它的核心就三个零件:XMLHttpRequest(主角)、异步处理(灵魂)、DOM操作(门面)。咱们用一个 "实时天气查询" 的例子,手把手拆一遍。
1. 主角登场:XMLHttpRequest 对象
这玩意儿就是浏览器派去服务器的 "信使",创建方式超简单:
javascript
运行
// 1. 雇个信使
const xhr = new XMLHttpRequest();
// 2. 告诉信使去哪儿、做什么(GET请求,查北京天气)
xhr.open('GET', 'https://api.weather.com/beijing', true);
// 第三个参数true:异步!关键中的关键
// 3. 信使出发
xhr.send();
这里的open方法有三个参数:请求方式(GET/POST)、接口地址、是否异步(几乎永远填 true)。send方法就是让信使出发,带不带 "礼物"(请求体)看需求 ——GET 请求不用带,POST 请求要在 send 里传数据。
2. 灵魂所在:异步回调怎么玩?
信使出去了,什么时候回来?总不能一直盯着吧?这时候就要给信使装个 "对讲机"(事件监听):
javascript
运行
// 信使回来时触发(不管成功失败)
xhr.onreadystatechange = function() {
// readyState=4:信使完成任务回到家
// status=200:服务器正常响应(绿灯)
if (xhr.readyState === 4 && xhr.status === 200) {
// 拿到服务器给的"包裹"(响应数据)
const weatherData = JSON.parse(xhr.responseText);
// 更新页面(DOM操作)
document.getElementById('weather').innerText = `北京今天${weatherData.temp}℃`;
}
};
这里有个容易踩坑的点:readyState的 5 种状态(0-4),很多人记不住。其实不用死记,理解成 "信使的工作流程" 就行:
- 0:刚雇了信使,还没说去哪儿(未调用 open)
- 1:告诉信使地址了,但还没出发(调用了 open,没调用 send)
- 2:信使到服务器了,服务器说 "收到请求"(send 已调用,响应头已接收)
- 3:服务器正在打包数据,信使在等(正在接收响应体)
- 4:信使带着包裹回家了(响应完成)
3. 现代升级:用 Promise 封装更优雅
原生回调写多了容易 "回调地狱",2025 年谁还这么干?咱们用 Promise 包一下,瞬间清爽:
javascript
运行
function request(url, method = 'GET', data = null) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
// 如果是POST,告诉服务器发的是JSON
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/json');
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`请求失败:${xhr.status}`));
}
}
};
// POST请求要发JSON字符串
xhr.send(data ? JSON.stringify(data) : null);
});
}
// 用的时候就像这样(async/await更舒服)
async function getWeather() {
try {
const data = await request('https://api.weather.com/beijing');
console.log('天气数据:', data);
} catch (err) {
console.error('出错了:', err);
}
}
看,这是不是和你用的 Axios 很像?其实 Axios 的底层,就是用 XMLHttpRequest 封装的(当然,它还加了拦截器、取消请求等高级功能)。
三、2025 年还学 Ajax?这 3 个场景非它不可
肯定有人说:"有 Axios 了,学 Ajax 干嘛?" 但这 3 个场景,不懂 Ajax 你根本玩不转:
1. 理解 Axios 的 "黑魔法"
比如 Axios 的 "取消请求" 功能,本质上是调用了xhr.abort();它的 "请求拦截器",其实是在xhr.send()之前修改请求头。懂了 Ajax,看 Axios 源码就像看说明书。
2. 处理特殊兼容性场景
某些老设备(比如工业级浏览器)不支持 Fetch API,但一定支持 XMLHttpRequest。这时候原生 Ajax 就是救命稻草。
3. 面试加分项
面试官问:"Fetch 和 Ajax 的区别?" 你可以答:"Fetch 是 Promise 风格的 API,返回的是 Response 对象需要二次处理;而 Ajax 基于 XMLHttpRequest,回调更原始,但兼容性更好..." 这种回答,不比 "我只用 Axios" 强?
四、避坑指南:这 5 个坑 90% 的人都踩过
1. 跨域报错?别只怪后端
跨域提示No 'Access-Control-Allow-Origin' header时,除了让后端加 CORS,前端也能临时解决:比如开发环境用 webpack-dev-server 代理:
javascript
运行
// vue.config.js 配置
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://真实接口地址',
changeOrigin: true, // 关键:假装自己是目标域的请求
pathRewrite: {'^/api': ''}
}
}
}
};
2. POST 请求发不出去?检查 Content-Type
默认情况下,xhr.send () 发的是text/plain类型,服务器可能不认。发 JSON 要加:
javascript
运行
xhr.setRequestHeader('Content-Type', 'application/json');
发表单数据要加:
javascript
运行
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3. 响应数据乱码?看 responseType
如果服务器返回的是 JSON,提前设置xhr.responseType = 'json',就不用手动 JSON.parse 了。
4. 重复请求坑死人
用户快速点两次按钮,会发两次请求。解决办法:发请求前取消上一次的:
javascript
运行
let xhr = null;
function fetchData() {
// 如果有未完成的请求,先取消
if (xhr && xhr.readyState !== 4) {
xhr.abort();
}
xhr = new XMLHttpRequest();
// ...后续逻辑
}
5. 异步顺序错了?用 async/await
多个请求有依赖关系(比如先查用户信息,再查用户订单),别嵌套回调,用 async/await:
javascript
运行
async function loadUserInfo() {
const user = await request('/user');
const orders = await request(`/orders?userId=${user.id}`);
// 按顺序执行,清爽!
}
五、总结:Ajax 不是 "老古董",而是前端的 "内功心法"
2025年的前端圈,新框架新工具层出不穷,但 Ajax 这种底层逻辑永远不会过时。就像练武功,招式可以变,但内力(对本质的理解)才是决定上限的关键。
最后留个思考题:你在项目中用 Ajax(或 Axios)踩过最离谱的坑是什么?怎么解决的?评论区交流一下,点赞最高的送一份《Ajax 实战手册》~