AJAX、Axios、Fetch 区别详解
快速对比表
| 特性 | AJAX (XMLHttpRequest) | Fetch API | Axios |
|---|---|---|---|
| 本质 | 技术概念/实现方式 | 原生浏览器API | 第三方JavaScript库 |
| 是否原生 | 原生API | 原生API | 第三方库,需引入 |
| 基于Promise | ❌ 使用回调 | ✅ 基于Promise | ✅ 基于Promise |
| 默认JSON | ❌ 需手动解析 | ✅ response.json() | ✅ 自动转换 |
| 请求取消 | ✅ XMLHttpRequest.abort() | ✅ AbortController | ✅ CancelToken/AbortController |
| 超时设置 | ✅ 原生支持 | ❌ 需自行封装 | ✅ 内置支持 |
| 进度监控 | ✅ 支持上传/下载进度 | ❌ 不支持 | ✅ 支持上传/下载进度 |
| 浏览器支持 | 几乎所有浏览器 | 现代浏览器(IE不兼容) | 现代浏览器(可polyfill) |
| 请求拦截器 | ❌ 不支持 | ❌ 不支持 | ✅ 请求/响应拦截器 |
| CSRF防护 | ❌ 需手动处理 | ❌ 需手动处理 | ✅ 内置支持 |
| 错误处理 | 状态码需手动检查 | 不reject HTTP错误码 | reject HTTP错误码 |
详细区别分析
1. AJAX (XMLHttpRequest)
// 传统 AJAX - 基于回调,语法繁琐
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
}
}
};
xhr.send();
优点:
- 最广泛的浏览器兼容性
- 支持进度事件(上传/下载)
- 支持超时设置
- 可以取消请求
缺点:
- 基于回调,易产生回调地狱
- 语法冗长复杂
- 需手动处理JSON转换
- 错误处理不够直观
2. Fetch API
// Fetch - 现代、简洁,但需处理HTTP错误
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));
// 主要局限:
// 1. 默认不发送cookie
// 2. 不会reject HTTP错误状态码
// 3. 不支持超时(需配合AbortController)
优点:
- 语法简洁,基于Promise
- 现代浏览器原生支持
- 支持流式处理
- 内置Request/Response对象
缺点:
- 不自动发送cookie(需设置credentials)
- 不会reject HTTP错误状态码(如404、500)
- 不支持请求取消(需AbortController)
- 无超时设置
- 不支持进度监控
- IE完全不支持
3. Axios
// Axios - 功能全面,开发者友好
axios.get('https://api.example.com/data', {
timeout: 5000,
headers: { 'X-Custom-Header': 'value' },
onUploadProgress: (progressEvent) => {
const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(`上传进度: ${percent}%`);
}
})
.then(response => {
console.log(response.data); // 自动JSON解析
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('请求被取消');
} else if (error.response) {
// HTTP错误状态码
console.log(`状态码: ${error.response.status}`);
} else if (error.request) {
// 请求发送失败
console.log('网络错误');
} else {
// 其他错误
console.log(error.message);
}
});
核心特性:
// 1. 拦截器功能
axios.interceptors.request.use(
config => {
// 请求前添加token
config.headers.Authorization = `Bearer ${token}`;
return config;
},
error => Promise.reject(error)
);
axios.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
// 统一处理401错误
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// 2. 请求取消
const source = axios.CancelToken.source();
axios.get('/api/data', {
cancelToken: source.token
});
// 取消请求
source.cancel('用户取消了请求');
// 3. 并发请求
Promise.all([
axios.get('/api/users'),
axios.get('/api/posts')
]).then(responses => {
const users = responses[0].data;
const posts = responses[1].data;
});
实际使用场景对比
场景1:发送带认证的GET请求
// AJAX
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.setRequestHeader('Authorization', 'Bearer token');
xhr.onload = function() { /* 处理响应 */ };
xhr.send();
// Fetch
fetch('/api/data', {
headers: { 'Authorization': 'Bearer token' },
credentials: 'include' // 发送cookie
});
// Axios
axios.get('/api/data', {
headers: { 'Authorization': 'Bearer token' }
});
场景2:处理HTTP错误
// AJAX - 手动检查状态码
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
success();
} else {
error();
}
}
};
// Fetch - 需要额外检查response.ok
fetch('/api/data')
.then(response => {
if (!response.ok) {
throw new Error('请求失败');
}
return response.json();
});
// Axios - 自动处理,HTTP错误会进入catch
axios.get('/api/data')
.then(response => success())
.catch(error => {
if (error.response) {
console.log('状态码:', error.response.status);
}
});
场景3:上传文件并监控进度
// AJAX - 支持进度监控
xhr.upload.onprogress = function(event) {
const percent = (event.loaded / event.total) * 100;
console.log(`上传进度: ${percent}%`);
};
// Fetch - 不支持进度监控
// 只能使用Content-Length估算
// Axios - 支持进度监控
axios.post('/api/upload', formData, {
onUploadProgress: function(progressEvent) {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`上传进度: ${percent}%`);
}
});
性能与大小对比
| 指标 | XMLHttpRequest | Fetch | Axios |
|---|---|---|---|
| 包大小 | 原生,0KB | 原生,0KB | ~13KB (gzipped) |
| 首次加载 | ✅ 最快 | ✅ 快 | ⚠️ 需下载 |
| 内存占用 | 较低 | 较低 | 稍高 |
| 性能 | 优秀 | 优秀 | 良好 |
选择建议
选择 XMLHttpRequest 当:
- 需要支持非常旧的浏览器(如IE8)
- 需要精确的上传/下载进度监控
- 项目要求零第三方依赖
选择 Fetch API 当:
- 仅支持现代浏览器
- 项目体积敏感,不想引入额外库
- 需要流式处理能力
- 开发简单的请求场景
选择 Axios 当:
- 需要完整的HTTP客户端功能
- 需要请求/响应拦截器
- 需要自动的JSON转换
- 需要处理多种错误类型
- 项目复杂度较高,需要统一配置
- 需要向后兼容性(可配置polyfill)
综合推荐
对于大多数现代Web项目,推荐使用 Axios,因为:
- 提供更好的开发者体验
- 完整的错误处理机制
- 拦截器功能便于统一管理
- 自动JSON转换减少样板代码
- 良好的向后兼容性
简单项目或库开发可考虑使用 Fetch API 以减少依赖。
特殊场景(如文件上传进度、超低浏览器要求)考虑 XMLHttpRequest。