AJAX、Axios 和 Fetch 对比总结
一、技术概述
1. XMLHttpRequest (AJAX)
- 概念:浏览器原生API,用于在后台与服务器交换数据
- 出现时间:1999年(ActiveX),2006年标准化
2. Axios
- 概念:基于Promise的HTTP客户端库
- 依赖关系:基于XMLHttpRequest封装
- 特点:支持浏览器和Node.js环境
3. Fetch API
- 概念:浏览器原生API,Promise-based
- 出现时间:2015年(ES6)
- 特点:现代浏览器内置,无需额外库
二、核心优缺点对比
| 特性 |
XMLHttpRequest (AJAX) |
Axios |
Fetch API |
|---|
| 语法简洁性 |
❌ 回调方式,代码冗长 |
✅ Promise链式调用,简洁 |
✅ Promise-based,较简洁 |
| 错误处理 |
❌ 需要监听多个事件 |
✅ 自动抛出HTTP错误状态 |
❌ 默认不处理HTTP错误(404等) |
| 请求取消 |
✅ 原生支持 .abort() |
✅ 支持 CancelToken/AbortController |
✅ 需结合AbortController |
| 超时设置 |
✅ 原生支持 |
✅ 内置超时配置 |
❌ 不支持原生超时 |
| 浏览器支持 |
✅ 全浏览器支持 |
✅ 全浏览器(通过polyfill) |
⚠️ IE不支持,需polyfill |
| 进度监控 |
✅ 原生支持上传/下载进度 |
✅ 支持进度监控 |
❌ 不支持上传进度 |
| 自动转换 |
❌ 手动处理JSON转换 |
✅ 自动JSON转换 |
⚠️ 需手动调用 .json() |
| 拦截器 |
❌ 不支持 |
✅ 请求/响应拦截器 |
❌ 不支持 |
| CSRF防护 |
❌ 手动设置 |
✅ 自动携带XSRF token |
❌ 手动设置 |
| 请求/响应结构 |
❌ 复杂,需手动封装 |
✅ 统一结构,易用 |
⚠️ 响应对象需手动处理 |
| 文件上传 |
✅ FormData支持 |
✅ FormData支持,更友好 |
✅ FormData支持 |
三、详细特性对比
1. 基本使用示例
// 1. XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.onload = () => console.log(xhr.responseText);
xhr.send();
// 2. Axios
axios.get('/api/data')
.then(response => console.log(response.data))
.catch(error => console.error(error));
// 3. Fetch
fetch('/api/data')
.then(response => {
if (!response.ok) throw new Error('HTTP error');
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));
2. 错误处理差异
// Axios:自动处理HTTP错误状态(非2xx)
axios.get('/api/not-found')
.catch(error => {
// 404等状态码会进入catch
console.log(error.response.status); // 404
});
// Fetch:需要手动检查状态
fetch('/api/not-found')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.catch(error => console.log(error));
3. 请求取消实现
// Axios (旧版)
const source = axios.CancelToken.source();
axios.get('/api/data', {
cancelToken: source.token
});
source.cancel('请求取消');
// Axios (新版) / Fetch
const controller = new AbortController();
fetch('/api/data', {
signal: controller.signal
});
controller.abort();
4. 拦截器(仅Axios支持)
// 请求拦截器
axios.interceptors.request.use(
config => {
config.headers.Authorization = 'Bearer token';
return config;
},
error => Promise.reject(error)
);
// 响应拦截器
axios.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
// 重定向到登录
}
return Promise.reject(error);
}
);
四、选择建议
选择 Axios 的情况
- 需要统一的错误处理机制
- 项目需要请求/响应拦截器
- 需要自动转换JSON数据
- 需要上传进度监控
- 需要向后兼容性(包括旧版浏览器)
- 项目已在Node.js中使用
选择 Fetch 的情况
- 现代浏览器项目,无需支持IE
- 希望减少第三方依赖
- 项目较小,简单请求为主
- 需要利用Service Workers
- 遵循原生API标准
选择 XMLHttpRequest 的情况
- 需要支持非常旧的浏览器
- 需要精确的上传/下载进度控制
- 项目已有成熟的封装
- 需要同步请求(极少情况)
五、最佳实践建议
现代项目首选:优先考虑Fetch API + 简单封装
企业级/复杂项目:推荐使用Axios,功能更完整
兼容性要求高:Axios + 适当polyfill
简单封装示例(解决Fetch痛点):
// 封装Fetch解决常见问题
async function httpRequest(url, options = {}) {
const { timeout = 8000, ...fetchOptions } = options;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...fetchOptions,
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// 自动根据Content-Type解析
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
return await response.json();
}
return await response.text();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
}
六、性能考虑
包大小
- Fetch:0KB(浏览器内置)
- Axios:~4KB(gzipped)
- XHR:0KB(浏览器内置)
请求速度
- 三者底层都是HTTP请求,性能差异可以忽略
- Axios有轻微封装开销,但影响不大
内存占用
总结表格
| 维度 |
推荐选择 |
理由 |
|---|
| 快速原型/简单项目 |
Fetch API |
无依赖,现代浏览器内置 |
| 生产级Web应用 |
Axios |
功能完整,错误处理完善 |
| 需要最大兼容性 |
Axios + polyfill |
支持所有浏览器环境 |
| 需要最少依赖 |
Fetch + 简单封装 |
保持轻量 |
| React Native项目 |
Axios |
跨平台一致性更好 |
最终建议:对于大多数现代Web项目,Axios提供了最佳开发体验和功能完整性;对于追求轻量和现代API的项目,可以选择Fetch并进行适当封装。