游侠网云服务,免实名免备案服务器 游侠云域名,免实名免备案域名

统一声明:

1.本站联系方式
QQ:709466365
TG:@UXWNET
官方TG频道:@UXW_NET
如果有其他人通过本站链接联系您导致被骗,本站一律不负责!

2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET
3.免实名域名注册购买- 游侠云域名
4.免实名国外服务器购买- 游侠网云服务
ajax和fetch有什么区别?前端必看的核心差异总结

这篇文章就针对前端最常遇到的“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-Typetext/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不支持

最后再给你点实践 ——都是我踩坑踩出来的“老司机经验”:

  • 新项目用现代框架(React、Vue3):优先选fetch,因为它更符合Promise和ES6+的语法,代码更简洁;
  • 维护老项目:用jQuery的$.ajax没问题,不用强行替换——除非你想优化代码结构;
  • 跨域请求:两者都需要后端设置CORS(比如Access-Control-Allow-Origin: *),但fetch的mode选项更灵活(mode: 'cors'是默认,mode: 'no-cors'用于不需要返回数据的请求);
  • 写fetch必做的两件事:检查response.ok(避免状态码错误)、解析数据(.json().text());
  • 兼容旧浏览器:用ajax,或者加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。