

统一声明:
1.本站联系方式QQ:709466365 TG:@UXWNET 官方TG频道:@UXW_NET 如果有其他人通过本站链接联系您导致被骗,本站一律不负责! 2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET 3.免实名域名注册购买- 游侠云域名 4.免实名国外服务器购买- 游侠网云服务
这篇文章就针对前端最常遇到的“ajax vs fetch”选择难题,把两者的区别拆成底层原理、语法逻辑、功能细节、兼容性四大块——从ajax依赖的XMLHttpRequest对象,到fetch基于Promise的原生API;从ajax的回调嵌套痛点,到fetch的链式调用优势;从cookie、请求头的处理差异,到旧浏览器的兼容坑,全是项目里天天要面对的重点。不管你是刚入门想打基础,还是老司机想优化代码,这份 能帮你一次性理清两者的边界,下次写请求时再也不用纠结“选哪个”,直接根据场景挑最顺手的工具!
你有没有过写接口请求时,明明都是发请求,可fetch总比ajax多一步数据解析?或者旧项目用ajax没问题,新项目用fetch却要补兼容?我去年帮一个做电商小程序的朋友调接口,他就是因为没搞懂两者的cookie处理差异,导致用户登录状态总失效,折腾了三天才解决。今天就把我踩过的坑、整理的核心差异掰碎了讲,都是前端项目里天天要面对的点,学完你再也不用纠结“选ajax还是fetch”。
从底层原理到语法,先搞懂两者的“出身”差异
要分清楚ajax和fetch,得先从“它们是什么”说起——这俩虽然都是发请求的工具,但“出身”完全不一样。ajax其实不是一门新技术,而是“异步JavaScript和XML”的缩写,本质是用XMLHttpRequest(简称xhr)对象实现异步请求;而fetch是HTML5新增的原生Promise API,是浏览器直接提供的,目的就是替代传统的xhr,更符合现代JavaScript的异步写法。
我之前维护一个2018年的老后台系统,用的是jQuery的$.ajax
,后来想换成fetch优化代码,结果第一个坑就来了:fetch没有xhr的readyState
(请求状态码),也没有onreadystatechange
事件,得用Promise的.then()
链式调用处理结果。比如ajax写起来是这样的:
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/user'); // 初始化请求
xhr.onreadystatechange = function() { // 监听请求状态变化
if (xhr.readyState === 4 && xhr.status === 200) { // 状态4=请求完成,状态码200=成功
const data = JSON.parse(xhr.responseText); // 手动解析JSON字符串
console.log(data);
}
};
xhr.send(); // 发送请求
而fetch是这样:
fetch('/api/user') // 直接调用fetch,返回Promise
.then(response => {
if (!response.ok) { // 检查状态码是否在200-299之间
throw new Error('请求失败'); // 主动抛错,进入catch
}
return response.json(); // 把Response对象转成JSON——这步90%的新手会忘!
})
.then(data => console.log(data)) // 拿到最终数据
.catch(error => console.error(error)); // 捕获错误
看到没?fetch的逻辑是“链式处理”:先发请求,再检查响应是否成功,再解析数据,最后用数据——我同事刚入门时就犯过“忘了解析”的错,以为fetch直接返回数据,结果打印出来是Response
对象,急得拍着桌子找我帮忙:“这玩意儿怎么不是JSON啊?”
再说说语法的“顺手程度”。以前用ajax写嵌套请求(比如先拿用户信息再拿订单),得写成“回调套回调”:
const xhr1 = new XMLHttpRequest();
xhr1.open('GET', '/api/user');
xhr1.onload = function() { // 第一个请求完成
const user = JSON.parse(xhr1.responseText);
const xhr2 = new XMLHttpRequest(); // 发第二个请求
xhr2.open('GET', /api/orders/${user.id}
);
xhr2.onload = function() { // 第二个请求完成
const orders = JSON.parse(xhr2.responseText);
console.log(orders);
};
xhr2.send();
};
xhr1.send();
这就是大家说的“回调地狱”,嵌套个两三层就乱得像毛线球——我以前维护过一个老项目,嵌套了五层回调,改代码时眼睛都花了。而fetch用Promise链式调用,逻辑就清爽多了:
fetch('/api/user')
.then(res => res.json()) // 解析用户数据
.then(user => fetch(/api/orders/${user.id}
)) // 用用户ID发订单请求
.then(res => res.json()) // 解析订单数据
.then(orders => console.log(orders)) // 拿到订单
.catch(err => console.error(err)); // 捕获所有错误
要是结合async/await
,写法更像同步代码,简直不要太顺手:
async function getOrders() {
try {
const userRes = await fetch('/api/user'); // 等待用户请求完成
const user = await userRes.json(); // 等待解析用户数据
const ordersRes = await fetch(/api/orders/${user.id}
); // 等待订单请求完成
const orders = await ordersRes.json(); // 等待解析订单数据
console.log(orders);
} catch (err) {
console.error('请求出错:', err);
}
}
我现在写新项目都优先用fetch,就是因为这种“线性逻辑”比回调嵌套舒服太多——尤其是遇到复杂的请求依赖,链式调用能让代码逻辑一目了然。
功能细节里的“隐藏坑”,才是开发中最容易踩的
光懂原理还不够,真正让你在项目里栽跟头的,往往是那些“看起来不重要”的细节。我朋友的电商小程序事件就是典型:他用fetch发请求,没加credentials
配置,导致用户登录后的session cookie没被携带,后端识别不了登录状态,用户加购商品时总提示“请登录”——折腾了三天,才发现是fetch的cookie处理和ajax不一样。
第一个坑:Cookie处理差异
ajax默认会自动携带当前域名的Cookie——比如你登录后,浏览器保存了session_id
的Cookie,ajax发请求时会自动把这个Cookie带过去,后端就能通过session_id
识别你的登录状态。但fetch不一样,它默认不携带Cookie,得手动加credentials: 'include'
配置才会带:
// fetch带Cookie的写法
fetch('/api/cart', {
credentials: 'include' // 关键配置!
})
我朋友就是没加这个,导致后端拿不到session_id
,以为用户没登录——你说这坑踩得冤不冤?
第二个坑:请求头(Headers)的默认值
ajax的$.ajax
(jQuery封装)很“贴心”:如果你传的是对象(比如data: { name: '张三' }
),它会自动把Content-Type
设为application/x-www-form-urlencoded
(表单格式)或者application/json
(JSON格式);但fetch不一样,它的默认Content-Type
是text/plain;charset=UTF-8
——上个月帮一个做教育类APP的前端调接口,他用fetch发POST请求,没设置Content-Type
,结果后端收不到JSON数据,急得直挠头:“我数据传了啊,怎么后端说没收到?”
我让他加上请求头配置,问题立刻解决:
fetch('/api/submit', {
method: 'POST', // POST请求
headers: {
'Content-Type': 'application/json' // 告诉后端“我发的是JSON”
},
body: JSON.stringify({ name: '张三', age: 25 }) // 把对象转成JSON字符串
})
你看,fetch虽然“原生”,但不如ajax“贴心”——它不会帮你做这些默认配置,得自己手动加。
第三个坑:兼容性问题
ajax的xhr对象早在IE7就支持了(虽然IE6要用ActiveXObject
,但现在几乎没人用IE6了);而fetch在IE 11及以下完全不支持——我之前维护一个企业官网,要兼容IE 10,只能用ajax,因为加fetch的polyfill(比如whatwg-fetch
)会增加代码体积,而且容易出bug(比如polyfill的response.json()
偶尔会解析失败)。
要是你得兼容旧浏览器,我 直接用ajax或者jQuery的$.ajax
;如果是新项目,用Chrome、Firefox、Edge这些现代浏览器,fetch完全没问题——毕竟现在连IE 11的市场占比都不到1%了(数据来自StatCounter,2024年5月)。
为了让你更直观,我整理了一个核心差异对比表,都是开发中高频遇到的点——你可以直接保存,下次写请求时对照着看:
差异点 | ajax(xhr) | fetch |
---|---|---|
底层依赖 | XMLHttpRequest对象 | 原生Promise API |
数据解析 | 需手动JSON.parse(responseText) | 需调用.response.json()/.text() |
Cookie携带 | 默认携带 | 需加credentials: ‘include’ |
默认Content-Type | application/x-www-form-urlencoded或application/json | text/plain;charset=UTF-8 |
兼容性 | 支持IE7+、所有现代浏览器 | 支持Chrome 42+、Firefox 39+,IE不支持 |
最后再给你点实践 ——都是我踩坑踩出来的“老司机经验”:
$.ajax
没问题,不用强行替换——除非你想优化代码结构;Access-Control-Allow-Origin: *
),但fetch的mode
选项更灵活(mode: 'cors'
是默认,mode: 'no-cors'
用于不需要返回数据的请求);response.ok
(避免状态码错误)、解析数据(.json()
或.text()
);whatwg-fetch
+es6-promise
的polyfill,但要测试清楚——我之前加polyfill时,遇到过response.json()
解析失败的问题,后来换成response.text()
再手动JSON.parse
才解决。你有没有踩过ajax或fetch的坑?比如cookie失效、数据解析错误?欢迎在评论区留言,我帮你分析分析——毕竟前端开发,踩坑多了才会变“老司机”嘛!
本文常见问题(FAQ)
ajax和fetch本质上是一回事吗?
不是哦,它们的“出身”完全不一样。ajax其实是“异步JavaScript和XML”的缩写,本质是用XMLHttpRequest(xhr)对象来实现异步请求的;而fetch是HTML5新增的原生Promise API,是浏览器直接提供的新技术,目的就是替代传统的xhr,更符合现代JavaScript的异步写法。
简单说,ajax是“基于xhr的解决方案”,fetch是“浏览器原生的新方案”,两者底层依赖的技术完全不同,这也是很多差异的根源。
为什么fetch写起来比ajax多一步数据解析?
因为两者返回的结果类型不一样。ajax用xhr对象发请求,请求完成后会拿到xhr.responseText,这是直接的字符串数据,你可以自己JSON.parse转成对象;但fetch返回的是一个Response对象,这个对象里包含了响应的状态码、 headers、 body等信息,不是直接的数据。
所以用fetch时,必须再调用一次.response.json()(或.text())把Response对象里的body解析成你需要的数据——这步很多新手都会忘,结果拿到Response对象就懵了,还以为请求失败。
为什么用fetch发请求时登录状态总失效?
这大概率是Cookie没携带的问题。ajax默认会自动携带当前域名的Cookie,比如你登录后浏览器保存的session_id,ajax发请求时会自动带过去,后端就能识别你的登录状态;但fetch不一样,它默认不携带Cookie,得手动加配置才行。
解决办法很简单,在fetch的配置里加一句credentials: ‘include’,这样请求就会带上Cookie了——我去年帮朋友调电商小程序接口时,就是因为没加这个配置,导致用户登录状态总失效,折腾了三天才解决。
用fetch发POST请求,后端为什么收不到数据?
很可能是请求头的Content-Type没设置对。ajax(比如jQuery的$.ajax)会贴心地帮你自动设置Content-Type,比如传JSON对象时会设为application/json;但fetch的默认Content-Type是text/plain;charset=UTF-8,后端如果 expecting JSON数据,就会收不到。
你只要在fetch的headers里手动加一句’Content-Type’: ‘application/json’,再把要传的数据用JSON.stringify转成字符串,后端就能正常接收了——上个月帮教育类APP调接口时,这个问题刚解决过,加了配置立刻好。
想兼容IE浏览器,能用fetch吗?
不太 哦。fetch在IE 11及以下版本完全不支持,哪怕你加polyfill(比如whatwg-fetch),也会增加代码体积,而且容易出bug——我之前维护企业官网时,加了polyfill后遇到过response.json()解析失败的问题,后来换成response.text()再手动JSON.parse才解决。
如果必须兼容IE 10或更低版本,还是老老实实用ajax吧,xhr对象早在IE7就支持了,兼容性更稳定,不用折腾polyfill。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
站长QQ:709466365 站长邮箱:709466365@qq.com