深入理解 Ajax:从 XMLHttpRequest 到 Fetch 与 Axios 的演进

275 阅读5分钟

在前端开发中,数据交互是核心能力之一。随着技术的发展,实现异步请求的方式也在不断演进。本文将从传统方案 XMLHttpRequest 入手,逐步过渡到现代方案 Fetch APIAxios,并通过手写 Ajax 的实践帮助初学者理解底层原理。最后,我们将对比不同方案的优缺点,助你选择最适合的工具。


一、Ajax 的核心概念

Ajax(Asynchronous JavaScript and XML) 是一种通过 JavaScript 在不刷新页面的情况下与服务器交换数据的技术。其核心依赖于 XMLHttpRequest 对象,结合 HTML、CSS 和 JavaScript 实现页面局部更新。虽然名称中包含 XML,但现代开发中 JSON 已成为主流数据格式。


二、传统方案:XMLHttpRequest

XMLHttpRequest 是 Ajax 的原生实现方式,虽然语法稍显繁琐,但理解其工作原理是掌握异步请求的基础。

1. 请求数据接口的步骤

// 1. 实例化 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();

// 2. 配置请求(方法、URL、是否异步)
xhr.open("GET", "https://api.example.com/data", true);

// 3. 发送请求
xhr.send();

// 4. 监听 readyState 变化
xhr.onreadystatechange = function () {
  // 5. 判断请求是否完成且成功
  if (xhr.readyState === 4 && xhr.status === 200) {
    // 6. 处理响应数据
    const responseData = JSON.parse(xhr.responseText);
    console.log("数据获取成功:", responseData);
  }
};

2. 关键属性与方法说明

  • readyState:表示请求的状态(0-4),4 表示请求完成。
  • status:HTTP 状态码(200 表示成功)。
  • responseText:服务器返回的原始文本数据(需手动解析 JSON)。
  • send(data):发送请求体(POST 请求时使用)。
  • setRequestHeader():设置请求头(如 Content-Type)。

3. 示例:GET 与 POST 请求

GET 请求

xhr.open("GET", "https://api.example.com/data?param=1", true);
xhr.send();

POST 请求

xhr.open("POST", "https://api.example.com/submit", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({ name: "Alice" }));

三、现代方案:Fetch API

Fetch API 是基于 Promise 的现代异步请求方案,语法简洁,支持链式调用,但需注意兼容性(IE 不支持)。

1. 请求数据接口的步骤

// 1. 调用 fetch 方法
fetch("https://api.example.com/data")
  // 2. 处理响应结果(解析 JSON)
  .then(response => response.json())
  // 3. 使用解析后的数据
  .then(data => {
    console.log("数据获取成功:", data);
  })
  // 4. 捕获错误
  .catch(error => {
    console.error("请求失败:", error);
  });

2. 关键特性

  • 基于 Promise:避免回调地狱,代码更简洁。
  • 自动处理 JSON:通过 response.json() 自动解析响应数据。
  • 模块化设计:将请求、响应、头信息等封装为独立对象(如 RequestResponse)。
  • 支持流式处理:通过 Stream 分块读取大文件,减少内存占用。

3. 示例:POST 请求

fetch("https://api.example.com/submit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ name: "Bob" })
})
  .then(response => response.json())
  .then(data => console.log("提交成功:", data))
  .catch(error => console.error("提交失败:", error));

四、Axios:基于 Fetch 的增强库

Axios 是一个广泛使用的 HTTP 客户端库,基于 Promise,并提供了更多实用功能,适用于浏览器和 Node.js 环境。

1. 核心特性

  • 自动转换 JSON:请求和响应数据自动转换为 JSON 格式。
  • 请求/响应拦截器:统一处理请求前和响应后逻辑(如添加 Token)。
  • 取消请求:通过 CancelTokenAbortController 中断请求。
  • 客户端防御 XSRF:自动设置 XSRF-TOKEN 并验证 Cookie。
  • 兼容性更好:通过 Polyfill 支持旧版浏览器(如 IE)。

2. 示例:GET 与 POST 请求

GET 请求

axios.get("https://api.example.com/data")
  .then(response => {
    console.log("数据获取成功:", response.data);
  })
  .catch(error => {
    console.error("请求失败:", error);
  });

POST 请求

axios.post("https://api.example.com/submit", {
  name: "Charlie"
})
  .then(response => {
    console.log("提交成功:", response.data);
  })
  .catch(error => {
    console.error("提交失败:", error);
  });

五、不同方案的对比

特性XMLHttpRequestFetch APIAxios
兼容性支持所有浏览器(包括 IE)现代浏览器支持,IE 不支持通过 Polyfill 支持 IE
语法复杂度繁琐(回调嵌套)简洁(基于 Promise)更简洁(封装更完善)
自动 JSON 转换需手动解析需手动解析自动转换
请求/响应拦截支持
取消请求支持 abort()需配合 AbortController支持 CancelToken
错误处理需监听 onerrorcatch 捕获catch 捕获

六、面试题:手写 Ajax

1. 实现思路

  • 创建 XMLHttpRequest 对象(兼容 IE)。
  • 配置请求(方法、URL、是否异步)。
  • 发送请求。
  • 监听 readystatechange 事件。
  • 处理响应数据。

2. 代码示例

function ajax(url, method = "GET", data = null, callback) {
  // 1. 创建 XMLHttpRequest 对象(兼容 IE)
  const xhr = new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP");

  // 2. 配置请求
  xhr.open(method, url, true);

  // 3. 设置请求头(POST 时需要)
  if (method === "POST") {
    xhr.setRequestHeader("Content-Type", "application/json");
  }

  // 4. 发送请求
  xhr.send(data ? JSON.stringify(data) : null);

  // 5. 监听 readyState 变化
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        // 6. 调用回调函数并传递响应数据
        callback(null, JSON.parse(xhr.responseText));
      } else {
        callback(new Error("请求失败:" + xhr.status));
      }
    }
  };
}

// 使用示例
ajax("https://api.example.com/data", "GET", null, (error, data) => {
  if (error) {
    console.error(error);
  } else {
    console.log("数据:", data);
  }
});

3. 代码解析

  • 兼容性处理:通过 ActiveXObject 支持 IE。
  • 请求头设置:POST 请求时需设置 Content-Type
  • 回调函数:使用 (error, data) 模式传递结果,符合 Node.js 风格。
  • 错误处理:通过 xhr.status 判断请求是否成功。

七、实际应用:JS 拉取数据接口

在实际开发中,通常使用 FetchAxios 实现数据交互。以下是一个使用 Axios 的完整示例:

// 获取用户列表
axios.get("https://api.example.com/users")
  .then(response => {
    const users = response.data;
    console.log("用户列表:", users);
  })
  .catch(error => {
    console.error("获取用户列表失败:", error);
  });

// 提交表单数据
axios.post("https://api.example.com/submit", {
  username: "Alice",
  email: "alice@example.com"
})
  .then(response => {
    console.log("提交成功:", response.data);
  })
  .catch(error => {
    console.error("提交失败:", error);
  });

八、总结与建议

  1. 选择合适的工具

    • 新项目或现代浏览器环境:优先使用 Fetch API,代码简洁且符合现代标准。
    • 需要兼容旧浏览器:使用 XMLHttpRequest 或引入 Polyfill。
    • 复杂项目:推荐 Axios,功能全面且易于维护。
  2. 手写 Ajax 的意义

    • 深入理解异步请求的底层原理。
    • 在无框架依赖时快速实现基础功能。
  3. 未来趋势

    • Fetch API 逐渐成为主流,但 Axios 仍因其丰富的功能占据重要地位。
    • 随着 Web 标准的演进,可能会出现更高效的异步通信方案(如 Web Streams API)。

通过本文的学习,你应该能够理解 Ajax 的演进过程,并根据实际需求选择合适的工具。无论是传统方案还是现代 API,掌握异步请求的核心思想才是关键。希望这篇博客能帮助你在前端开发的道路上更进一步!