
其实三者的差异藏在使用成本、功能边界、兼容性里:Ajax依赖jQuery、易陷回调地狱;Axios用Promise封装、自带拦截器和错误处理,是“懒人友好型”;Fetch作为浏览器原生API,看似轻便却要手动处理状态码、JSON转换,甚至兼容旧浏览器得加polyfill。
这篇文章不聊基础用法,只挖核心优缺点和场景适配——比如需要快速开发选谁?追求原生体验避坑什么?老项目重构该换哪个?帮你把三者的差异掰碎了讲清楚,看完就能根据项目需求精准选工具,再也不用在“选A还是选B”里纠结。
你有没有过这种情况?写前端项目要调接口,看着Ajax、Axios、Fetch三个选项,明明都能发请求,可就是拿不准选哪个——选老的Ajax怕麻烦,选新的Fetch又怕踩坑,选Axios又担心是不是真的适合自己的项目?我之前帮朋友改一个电商项目的前端请求逻辑时,就犯过这个愁:他原来用的是Ajax,回调嵌套得像千层饼,改个错误处理要翻半天代码;后来试了Fetch,结果忘了处理404状态码,用户下单失败的时候连提示都没有;最后换成Axios,才终于把拦截器和统一错误处理搞定,上线后bug少了一半。今天我就把这三个工具的优缺点掰碎了讲,不用记复杂概念,跟着我的实操经验走,你看完就能直接选对工具。
先搞懂:三个工具到底是什么?别被名词唬住
其实这三个工具的本质特别简单,别被“异步JavaScript和XML”“Promise API”这种名词唬住——我用大白话给你翻译一遍:
Ajax:不是新东西,是“老派请求工具”的代表
Ajax全称是“异步JavaScript和XML”,但你不用记这个——它本质上就是用浏览器自带的XMLHttpRequest对象发请求。我最早学前端的时候,写Ajax得引jQuery,因为原生的XMLHttpRequest写起来太麻烦:要写open()
、send()
,还要监听onreadystatechange
事件,回调函数里还要判断readyState
是不是4(请求完成)、status
是不是200(成功),稍微漏一步就出问题。比如你要查商品库存,原生Ajax得这么写:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/stock', true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
}
};
xhr.send();
你看,是不是要写一堆重复的代码?后来jQuery把Ajax封装成了$.ajax()
,才稍微方便点,但还是逃不掉“回调地狱”——比如先查用户信息、再查订单、再查物流,代码就会变成:
$.ajax({ url: '/api/user' }).done(function(user) {
$.ajax({ url: '/api/order', data: { userId: user.id } }).done(function(order) {
$.ajax({ url: '/api/logistics', data: { orderId: order.id } }).done(function(logistics) {
// 处理物流信息
});
});
});
嵌套三层之后,代码就跟缠在一起的耳机线似的,改个逻辑要翻半天。
Fetch:浏览器原生的“新工具”,但要自己踩坑
Fetch是浏览器后来推出的原生Promise API,目的就是代替XMLHttpRequest——它用Promise封装,写法更简洁。比如查库存,用Fetch只要写:
fetch('/api/stock')
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.log(err));
我第一次用Fetch的时候,觉得“哇塞好简单”,结果很快就踩了坑:有一次发POST请求,传的是JSON数据,但忘了设置headers: { 'Content-Type': 'application/json' }
,结果后端根本收不到数据;还有一次,接口返回401(未授权),我以为catch
会捕获到,结果发现Fetch的catch
只捕获网络错误(比如断网),像404、500这种HTTP错误不会进catch
——得自己判断response.ok
是不是true
(response.ok
只有状态码200-299时才是true
)。我朋友的电商项目就是因为这个踩坑:用户登录过期的时候,接口返回401,但Fetch没进catch
,前端没给提示,用户点了好几次下单按钮都没反应,投诉了好几个。
Axios:第三方“懒人工具”,把麻烦事都帮你做了
Axios是一个第三方Promise请求库,本质上是封装了浏览器的XMLHttpRequest(或者Node.js的http模块)。它的核心优势就是“省心”——把你能用得到的功能都帮你做好了:比如自动转换JSON数据(不用自己写JSON.parse()
)、拦截器(统一加请求头、处理错误)、取消请求(避免重复提交)。我之前做新闻资讯项目的时候,用Axios的请求拦截器做了统一的loading处理:
axios.interceptors.request.use(config => {
// 发请求前显示loading
document.getElementById('loading').style.display = 'block';
return config;
});
axios.interceptors.response.use(response => {
// 请求完成后隐藏loading
document.getElementById('loading').style.display = 'none';
return response;
});
只需要写一次拦截器,所有请求都能用,不用在每个请求里重复写loading逻辑。还有错误处理,Axios会把HTTP错误(比如404、500)直接抛到catch
里,不用自己判断response.ok
:
axios.get('/api/stock')
.then(res => console.log(res.data))
.catch(err => {
// 直接拿到错误信息
console.log('请求出错了:', err.response.data);
});
是不是比Fetch省心多了?
为了让你更清楚,我做了个表格,把三个工具的核心特性对比了一下:
工具名称 | 核心本质 | 常用场景 | 最大优势 | 最大痛点 |
---|---|---|---|---|
Ajax | 原生XMLHttpRequest封装(多为jQuery) | 老项目维护、兼容旧浏览器 | 兼容所有浏览器 | 写法繁琐、易陷回调地狱 |
Fetch | 浏览器原生Promise请求API | 轻量级项目、追求原生体验 | 无需引入第三方库 | 需手动处理状态码、headers和兼容 |
Axios | 第三方Promise请求库(封装XHR/Node.js http) | 大部分现代项目(React/Vue等) | 功能齐全(拦截器、统一处理) | 需引入第三方库 |
直接用:不同场景选哪个?跟着我的实操经验走
其实选工具的逻辑很简单:先看你的项目场景,再看工具的优缺点——不用追求“最新”,适合自己的才是对的。
场景1:老项目维护,不想动太多代码——选Ajax
如果你的项目是几年前的老项目(比如用jQuery 1.x),或者需要兼容IE8这种旧浏览器,那继续用Ajax没问题。我之前改一个企业官网的前端时,它用的是jQuery 1.8,引Axios的话要考虑兼容性(Axios不支持IE8),干脆就用$.ajax()
——只是把原来的回调改成了Promise写法($.ajax().then()
),这样既不用动太多代码,又解决了回调地狱的问题:
// 原来的回调写法
$.ajax({
url: '/api/user',
success: function(user) { / 处理用户信息 / },
error: function(err) { / 处理错误 / }
});
// 改成Promise写法,避免嵌套
$.ajax({ url: '/api/user' })
.then(user => $.ajax({ url: '/api/order', data: { userId: user.id } }))
.then(order => $.ajax({ url: '/api/logistics', data: { orderId: order.id } }))
.then(logistics => { / 处理物流信息 / })
.catch(err => { / 统一处理错误 / });
但要注意:老项目里的Ajax请求一定要加统一的错误处理——比如用$.ajaxSetup()
设置全局的error
回调,避免每个请求都写一遍:
$.ajaxSetup({
error: function(xhr, status, err) {
console.log('请求出错了:', err);
alert('操作失败,请重试');
}
});
场景2:轻量级项目,不想引第三方库——选Fetch,但要避坑
如果你做的是轻量级项目(比如一个单页的工具网站、静态页面),不想引Axios这种第三方库,那可以用Fetch——但一定要做好这3点避坑:
response.ok
,不然404、500不会进catch
:fetch('/api/stock')
Content-Type.then(response => {
if (!response.ok) throw new Error(response.statusText); // 抛出HTTP错误
return response.json();
})
.then(data => console.log(data))
.catch(err => console.log(err));
设置headers:发POST请求传JSON数据时,一定要加 :
javascript
fetch('/api/order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: 123, num: 2 })
});
whatwg-fetch
兼容旧浏览器:如果要兼容IE11或iOS10以下的浏览器,得加 这个polyfill(可以用npm装,或者引CDN)。
whatwg-fetch我之前做一个个人博客的评论功能时,用了Fetch——因为博客是静态页面,不想引额外的库。但上线后发现IE用户没法提交评论,后来加了
才解决。
场景3:现代项目(React/Vue等),要效率和稳定——选Axios,没错
如果你的项目是React、Vue或者Angular的现代项目,我优先推荐Axios——它的功能太适合现代项目了:
拦截器:统一加请求头(比如token)、处理响应数据。我做CRM系统的时候,所有请求都要带token,用请求拦截器统一加:
javascript
Bearer ${token}axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization =
;
return config;
});
headers: { Authorization: ... }
不用在每个请求里写
,省了好多重复代码。
catch统一错误处理:Axios会把HTTP错误直接抛到 里,不用自己判断
response.ok。比如:
javascript
axios.get('/api/stock')
.then(res => console.log(res.data))
.catch(err => {
// err.response里有状态码、错误信息
console.log('请求出错了:', err.response.status, err.response.data);
alert(err.response.data.msg || '操作失败');
});
取消请求:避免重复提交。我做搜索功能时,用户输入关键词每输一个字符就发一次请求,用CancelToken取消上一次的请求:
javascript
let cancel;
function search(keyword) {
// 取消上一次的请求
if (cancel) cancel();
axios.get('/api/search', {
cancelToken: new axios.CancelToken(c => cancel = c)
})
.then(res => console.log(res.data))
.catch(err => {
if (axios.isCancel(err)) return; // 忽略取消请求的错误
console.log(err);
});
}
baseURL
我朋友的电商项目换成Axios后,统一错误处理的代码减少了80%,原来要在每个请求里写的loading逻辑,现在只需要写一次拦截器——真的省了好多时间。
还有个小技巧:用Axios的时候,可以设置
,这样请求地址不用写全路径:
javascript
axios.defaults.baseURL = ‘https://api.example.com’;
// 之后发请求只要写相对路径
axios.get(‘/stock’); // 相当于https://api.example.com/stock
这样改域名的时候,只需要改
baseURL,不用改所有请求地址,超方便。
其实选工具的核心逻辑就一句话:看你的项目需要什么——老项目要兼容,选Ajax;轻量级项目要原生,选Fetch(记得避坑);现代项目要效率,选Axios。我之前帮朋友改项目的时候,就是这么选的:他的电商项目是Vue3的现代项目,需要统一的拦截器和错误处理,选Axios刚好;如果是他的个人博客(静态页面),就选Fetch;如果是他的老官网(jQuery),就选Ajax。
如果你按我说的试了,或者有什么疑问,欢迎在评论区告诉我——比如你用Axios做了拦截器,或者用Fetch解决了状态码问题,都可以留言,咱们一起避坑!
我第一次用Fetch的时候,踩的第一个大坑就是没处理response.ok——那时候做商品搜索功能,接口返回404(比如用户搜了个不存在的商品),我以为catch会接住错误,结果页面啥提示都没有,用户点好几次搜索按钮没反应,我还以为是按钮绑定事件错了,查控制台才发现:Fetch的catch只管“网络层面的错误”,比如断网、连不上服务器,像404(资源不存在)、500(服务器崩了)这种“HTTP状态码错误”,它根本不当事儿!得自己在then里先判断response.ok是不是true——只有状态码在200-299之间,response.ok才是true,不然就得主动抛个错误,比如throw new Error(response.statusText),这样catch才能接住,用户才会看到“搜索失败”的提示。
还有发POST请求传JSON数据的时候,千万别忘加Content-Type头!我之前给后端传订单信息,用Fetch写了个POST请求,body里明明用JSON.stringify转了数据,结果后端说“没收到参数”,查了半天才搞懂:Fetch默认的Content-Type是text/plain; charset=UTF-8,后端接口要是 expects JSON,根本解析不了这个格式——得手动在请求配置里加个headers: { ‘Content-Type’: ‘application/json’ },不然你传的JSON就跟没写一样,后端接收不到。
最后就是旧浏览器的兼容问题,要是你项目得照顾IE11或者iOS10以下的用户,直接用Fetch肯定翻车——我之前做公众号的H5页面,用Fetch发请求,结果iPhone 6的用户反馈“点按钮没反应”,查浏览器兼容表才发现:iOS10及以下的Safari、IE11根本不支持Fetch API!得引个whatwg-fetch的polyfill(比如用npm装了之后import进去,或者直接引CDN链接),把Fetch的功能补上,不然这些用户的请求根本发不出去,页面就跟卡死了一样。
为什么现代项目更推荐用Axios?
Axios的核心优势是“省心”——它基于Promise封装,自带拦截器(统一加请求头、处理响应)、自动转换JSON数据、统一错误处理等功能,刚好匹配现代项目(如React/Vue)的高效开发需求。相比Fetch,它不用手动处理状态码、headers;相比Ajax,它避免了回调地狱,能大幅减少重复代码和bug。
Fetch使用时需要注意哪些“坑”?
Fetch作为原生API,需手动处理三点:
老项目维护时,Ajax怎么优化?
老项目用Ajax(多为jQuery的$.ajax())可做两点优化:
Axios引入第三方库会不会影响性能?
Axios的体积很小(gzip压缩后约10KB),对现代项目的性能影响几乎可忽略。相比它带来的开发效率提升(如拦截器减少重复代码、统一错误处理降低bug率),引入第三方库的成本远小于收益——毕竟开发时间和维护成本比这点体积重要得多。
三个工具的兼容性到底怎么选?
兼容性差异主要看项目需求: