JS 基础: 取消 Ajax 请求(fetch abort)
admin
2024-01-18 04:20:22
0

JS 基础: 取消 Ajax 请求(fetch abort)

文章目录

  • JS 基础: 取消 Ajax 请求(fetch abort)
  • 完整代码示例
  • 背景
  • 代码实现
    • 0. 没有正确 cancel
    • 1. 添加序列号
    • 2. fetch 取消请求
  • 更多思考
    • RxJS 实现
  • 参考链接

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/front_end/javascript/js_fetch_abort

背景

前端同学一定绕不开的一个基础能力便是向后端发起请求,最通用的便是基于 HTTP 协议与后端进行交互。不论是直接使用原生的 XHR API、axios,还是后来的 fetch API 都好。

这些请求都会会返回所谓的 Promise(或是基于 callback)的形式,然而有时候请求与请求间的响应时序是程序员所不能控制的,因此在回调函数、then 的处理上我们应该更加小心,对于同一种请求的重复发送应该进行正确的 cancellation,来保证最终更新到前端的状态永远是最新的数据。

代码实现

0. 没有正确 cancel

我们先来看看一般场景中常见的写法,没有考虑请求的 cancellation

useEffect(() => {getUserInfoAPI(URL, { body: { id } }).then((userInfo) => {setUserInfo(userInfo)})
}, [id])

如上代码,乍看之下没啥问题,但是实际上存在一种隐患是,当 id 在短时间内频繁变换的时候,getUserInfoAPI 会被调用多次,这时候多次请求之间的顺序实际上是不一定被保证的(这里的例子比较极端,常见场景之下也容易出现多个地方发起请求并同时掉用相同 API 并且修改相同状态的场景)。

这时候我们对于老旧需要废弃的请求就应该进行所谓的 cancellation,不去响应时序上已经无效的请求数据

1. 添加序列号

最直接的做法,那我们就为每一个请求添加序号,保证只更新最新状态咯

const userInfoAPISeq = useRef(0);
useEffect(() => {const seq = userInfoAPISeq.current = userInfoAPISeq.current + 1;getUserInfoAPI(URL, { body: { id } }).then((userInfo) => {if (seq === userInfoAPISeq.current) {setUserInfo(userInfo)}})
}, [id])

但是这样看起来实在不是非常优雅

2. fetch 取消请求

接下来我们介绍 fetch API 所提供的取消请求的能力,就是利用 AbortController 类来实现

useEffect(() => {const controller = new AbortController();getUserInfoAPI(URL, {body: { id },signal: controller.signal,}).then((userInfo) => {if (id === userInfoAPISeq.current) {setUserInfo(userInfo)}}).catch((error) => {if (error.name === 'AbortError' &&error instanceof DOMException) {// Response of abort}});// at some pointcontroller.abort();
}, [id])

我们只需要在 fetch API 的 option 里面传入一个 signal,然后后面使用 controller.abort 方法就能够取消请求,fetch 方法会自动将 response 置为 error 并且返回指定类型的 Exception 和 name。

更多思考

实际上经过测试之后发现,这些类似的 cancel 方法实际上仅仅只是前端层面上的取消,请求只要抵达后端就会进行相应的处理,因此在 cancel 上有几个点可以思考

  1. Cancel 只对拿数据的 get 方法有实际的意义,对于 post 请求相关的操作实际上还是会影响后端部分的持久化,这里再做 cancel 就显得没什么意义
  2. Abort vs Ignore:这时候到底是调用指定的 cancel 方法(abort 或是 axios 也提供了一个 cancel 的方式);又或是像第一种方法仅仅通过忽略非最后一次的请求结果即可。两种方法实际上后面看来区别并不大

RxJS 实现

这时候作者发现如果仅仅只是依赖忽略请求结果也能达到相同效果的话,使用 RxJS 将请求封装成一个 Observable 会看起来更加优雅

const getUserInfo = (() => {subject.pipe(// debounce(100)map(() => from(getUserInfoAPI())),switchAll()).subscribe((userIfno) => {setUserInfo(userInfo)});return () => {subject.next();}
})()getUserInfo();

利用 RxJS 的 Observable 模型,将每一个请求作为一个 Observable 来管理,我们就可以很轻易的利用 RxJS 提供的工具链进行 debounce、switchAll 来聚合代码逻辑

参考链接

TitleLink
Fetch: Aborthttps://javascript.info/fetch-abort
AbortController - MDNhttps://developer.mozilla.org/en-US/docs/Web/API/AbortController
Subject - Rxjshttps://rxjs.dev/guide/subject

相关内容

热门资讯

汪洪彬酒海“逆行”一生,何处是... 在贵州茅台镇的赤水河沿岸,酒香已飘荡数百年。这片土地孕育了无数酿酒人,而汪洪彬的故事,恰似一杯陈年酱...
原创 营... 大家分享几道被不少人称赞的家常美食,营养均衡又美味可口,非常下饭,做法特别简单,食材也是我们日常生活...
景山万春亭数故宫的脊兽:高端私... 在旅游的世界里,选择一家靠谱又有特色的旅行社至关重要。今天,就为大家带来一份旅行社排行榜,让我们一起...
新华视点|多元文旅绘就暑期画卷... 暑期文旅消费持续升温,各地通过多元举措激活市场活力,“文旅+”融合模式不断拓展。 ■设施升级添活力...
“避暑游”总搜索量大涨近200... 进入7月下旬,暑期出游高峰进入“中场”时段,旅游市场出现新的变化与特点。记者从本地旅行社和相关平台获...
奇幻自然课堂,新南威尔士州的亲... 随着家庭旅行从传统的观光体验转变为代际共同成长的重要仪式,现代父母对旅程的期待也在不断提升。美团联合...
文旅融合新名片!贵旅集团推动多... 本文转自:人民网-贵州频道7月26日,暮色下的多彩贵州城流光溢彩、歌舞飞扬。数支专业乐队以《痴心绝对...
西苑医院脾胃病科举办“胃爱守护... 近日,中国中医科学院西苑医院脾胃病科在门诊楼一层大厅举办 “胃爱守护・食刻舒心” 胃食管反流病专病义...
原创 “... “三伏不补,一年受苦”!三伏天是一年中最热、最潮湿的日子,人就像在 “桑拿房” 里待着,一动就出汗,...
贵州威宁举办避暑旅游季活动:“... 7月28日,2025年雪山灼甫“村歌”示范展示暨“我们的中国梦·文化进万家”贵州省威宁自治县避暑旅游...
水韵江苏 风雅德比|盐城VS常... 当盐渎新城的呦呦鹤鸣,应和着滩涂的潮汐,激荡起明代杨瑞云笔下“苍茫一气接乾坤,巨浪长风日夜喧”的壮阔...
带孩子去新疆游玩15天费用攻略... 带孩子去新疆怕预算超支又玩不尽兴?去年我带 7 岁女儿的十五天跟团游堪称 “完美范本”!网上找到的导...
共赴星河之约,枕星入眠!“恰西... 七月的巩留,云朵把影子投在起伏的恰西草原,牛羊像撒落的珍珠,雪岭云杉在天边排成长岗......这片 ...
让世界认识四川,剑门关国家5A... 爱旅游,爱生活。旅游可以放松自己的心情,宽阔自己的心境,你有好久没来一场说走就走的旅行,忘掉不顺心,...
受用的四川旅行五天方案,成都旅... 宝子们,四川,宛如一颗镶嵌在中国西南的璀璨明珠,散发着独特而迷人的魅力。它有着“天府之国”的美誉,这...
九公山公墓网红墓园:九公山名人... 当“特种兵旅游”的热潮退去,年轻人开始用脚步丈量历史的厚度。在九公山长城纪念林,一群特殊的“追星族”...
西北环线8日深度游,大西北经典... 西北环线8日深度游,大西北经典路线全攻略,这样走不踩雷! 想要一次看遍草原、沙漠、湖泊和丹霞的极致...