以为 Ajax 是老古董?2025 它依然是区分初级和资深前端的试金石

83 阅读5分钟

以为 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 实战手册》~