ajax、axios、fetch有哪些区别

37 阅读3分钟

AJAX、Axios、Fetch 区别详解

快速对比表

特性AJAX (XMLHttpRequest)Fetch APIAxios
本质技术概念/实现方式原生浏览器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}%`);
    }
});

性能与大小对比

指标XMLHttpRequestFetchAxios
包大小原生,0KB原生,0KB~13KB (gzipped)
首次加载✅ 最快✅ 快⚠️ 需下载
内存占用较低较低稍高
性能优秀优秀良好

选择建议

选择 XMLHttpRequest 当:

  • 需要支持非常旧的浏览器(如IE8)
  • 需要精确的上传/下载进度监控
  • 项目要求零第三方依赖

选择 Fetch API 当:

  • 仅支持现代浏览器
  • 项目体积敏感,不想引入额外库
  • 需要流式处理能力
  • 开发简单的请求场景

选择 Axios 当:

  • 需要完整的HTTP客户端功能
  • 需要请求/响应拦截器
  • 需要自动的JSON转换
  • 需要处理多种错误类型
  • 项目复杂度较高,需要统一配置
  • 需要向后兼容性(可配置polyfill)

综合推荐

对于大多数现代Web项目,推荐使用 Axios,因为:

  1. 提供更好的开发者体验
  2. 完整的错误处理机制
  3. 拦截器功能便于统一管理
  4. 自动JSON转换减少样板代码
  5. 良好的向后兼容性

简单项目或库开发可考虑使用 Fetch API 以减少依赖。

特殊场景(如文件上传进度、超低浏览器要求)考虑 XMLHttpRequest