关于 Ajax 有必要取消吗,请求如何取消?
假如你熟悉 xhr
,会知道 Ajax 其实可以前端主动取消,使用的是 XMLHttpRequest.abort()
。
当然现在也不是刀耕火种的时代,除了面试,可能基本不会手写 xhr
,在无人不知的 axios
中,有两种取消方法:
首先是老式 cancelToken:
const CancelToken = axios.CancelToken
const source = CancelToken.source()axios.get('/user/12345', {cancelToken: source.token,}).catch(function (thrown) {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message)} else {// handle error}})axios.post('/user/12345',{name: 'new name',},{cancelToken: source.token,}
)// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.')
然后是新玩意(其实也不新)AbortController:
const controller = new AbortController()axios.get('/foo/bar', {signal: controller.signal,}).then(function (response) {//...})
// cancel the request
controller.abort()
cancelToken 和 signal 传到 axios 之后,都会以某种机制调用 XMLHttpRequest.abort()
。
onCanceled = (cancel) => {if (!request) {return}reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel)request.abort()request = null
}config.cancelToken && config.cancelToken.subscribe(onCanceled)
if (config.signal) {config.signal.aborted? onCanceled(): config.signal.addEventListener('abort', onCanceled)
}
cancelToken 是利用发布订阅模式通知 axios 取消请求,虽然这部分是 axios 自己实现的,但是源自于一个 tc39 提案 cancelable promises proposal,不过这个提案被废弃了。
而 AbortController 是已经可以在浏览器使用的接口,顾名思义,这就是一个专门用于中止行为的控制器。mdn 的举例用的也是 Ajax 请求,不过是至潮至 in 的 fetch,从中可见 axios 跟 fetch 的实践是一致的:
function fetchVideo() {controller = new AbortController() // 新建一个 controllerconst signal = controller.signalfetch(url, { signal }) // 在 fetch 方法传入 signal.then(function (response) {console.log('Download complete', response)}).catch(function (e) {console.log('Download error: ' + e.message)})
}abortBtn.addEventListener('click', function () {if (controller) controller.abort() // 调用 controller.abort 取消 fetchconsole.log('Download aborted')
})
AbortController 的其他用途
当然 AbortController 不只有中止 Ajax 一个功能,通过查看 dom 规范文档还能看到两个使用示例:
一个比较实用的例子是用 AbortController 取消事件监听:
dictionary AddEventListenerOptions : EventListenerOptions {boolean passive = false;boolean once = false;AbortSignal signal;
};
通过向 AddEventListener
传入 signal
,运行 abort()
即可取消事件监听,这个方法对匿名回调函数尤其有用。
另一个例子是用于中止 promise。这是一个比较简洁且自文档的方法……不过其实实现这个功能也不是非要 AbortController 才能做到,只要想办法拿到 promise 的 reject
就好了。我觉得这个例子的重点偏向于学会使用 signal 的 onabort:
const controller = new AbortController();
const signal = controller.signal;startSpinner();doAmazingness({ ..., signal }).then(result => ...).catch(err => {if (err.name == 'AbortError') return;showUserErrorMessage();}).then(() => stopSpinner());// …controller.abort();function doAmazingness({signal}) {return new Promise((resolve, reject) => {signal.throwIfAborted();// Begin doing amazingness, and call resolve(result) when done.// But also, watch for signals:signal.addEventListener('abort', () => {// Stop doing amazingness, and:reject(signal.reason);});});
}
总之,signal 就是个简易发信器,而且功能偏向于取消某操作。如果在某种情况下不想自己实现一个 pubsub 对象的话,用这个就完事了。
AbortController 的介绍就到此为止吧,不知道大家有没有逐渐忘记标题……最后是想讨论一下,取消 Ajax 到底有没有用?
取消还是不取消,这是个问题
事实上,这个 Ajax 取消只是前端自说自话,后端并不知道要中止,发过去的请求还是要执行的,后端没有特殊处理的话, 10s 的请求你取消了后端也仍然在费劲地跑。
那么在一些文章中看到的“优化”,所谓“取消请求,只保留最后一个”是否真的有意义呢?
分情况讨论,对于 POST 等修改数据的请求,每次发送即使返回慢,服务器也已经在处理了,取消上一个 POST 再重复发一个无疑是弱智行为。
对于 GET,且仅针对某些极限操作,或许有一点效果,例如:获取一个超长 table,结果没拿到,然后用户就用搜索快速返回少量数据并且渲染了,等到超长 table 真正返回就会覆盖掉搜索的数据,这个情况 cancel 是真的有效的。另外还有下载上传的取消,不过估计也很少会用到。
最后再说一个有道理但是事实上也是没什么用的好处:cancel 之后能省一个请求位置,毕竟浏览器一个域名的同时请求数量是有限制的,更多情况下,比 cancel 更常见的 timeout 更实用。嗯……除非同时排着五六个超慢请求,否则轮转还是比较快的……
个人建议是,说到底这个所谓“取消”都是极特殊情况的特殊处理,知道这回事就好了,没有必要没事就在拦截器里整个取消操作。
参考
dom spec (https://dom.spec.whatwg.org/)
GitHub axios (https://github.com/axios/axios)
mdn AbortController (https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
本文系转载,阅读原文:https://ssshooter.com/2022-06-23-cancel-ajax/
关于 Ajax 有必要取消吗,请求如何取消?相关推荐
- (Ajax)axios源码简析(三)——请求与取消请求
传送门: axios源码简析(一)--axios入口文件 axios源码简析(二)--Axios类与拦截器 axios源码简析(三)--请求与取消请求 请求过程 在Axios.prototype.re ...
- axios取消接口请求
自己碰到的问题,扒了很多文档才理清楚,当做是笔记记下来 说到取消接口请求,可能没碰到这样的坑冷不丁还有点懵,为什么会有取消请求这回事,既然决定要请求这个接口了又要取消它,岂不是有点画蛇添足的操作? 1 ...
- 关于 axios 取消重复请求的分析
前言 关于取消重复请求,最重要的是这么做的意义,而不在于代码的实现 其实,我觉得,绝大部分能够想到的应用场景,都可以通过防抖.节流方式实现,比如实时搜索,比如重复订单提交.比如上拉获取最新数据等 我们 ...
- 输入框实时搜索优化,减少请求次数、取消无用请求
背景 用户在输入框输入内容的同时进行搜索,针对搜索实时搜索结果进行展示 问题 如果不做处理,只监听输入框的input事件或者键盘按下弹起事件,实时对文本内容进行搜索,往往因为网络波动问题可能会造成结果 ...
- mvc ajax get请求,springMVC 中 ajax get 请求和 post 请求的坑以及参数传递
1, ajax 请求 无论为 post ,或者 get ,url中带有?形式的参数,后台都能以String类型变量接收,变量名称和参数名称必须一致 前台ajax: $.ajax( "prod ...
- ASIHTTPRequest取消异步请求
取消异步请求 首先,同步请求是不能取消的. 其次,不管是队列请求,还是简单的异步请求,全部调用[ request cancel ]来取消请求. 取消的请求默认都会按请求失败处理,并调用请求失败dele ...
- 注意ajax的同步和异步请求
2019独角兽企业重金招聘Python工程师标准>>> 默认 一般ajax 或者 ajax工具 都是 异步请求的. 但是 在开发中,使用了一个 开源的 前端ui里面自带的ajax工 ...
- jQuery中ajax的4种常用请求方式
jQuery中ajax的4种常用请求方式:1.$.ajax()返回其创建的 XMLHttpRequest 对象. $.ajax() 只有一个参数:参数 key/value 对象,包含各配置及回调函数信 ...
- 单页面axios_Axios封装之取消重复请求和接口缓存
在平时的单页面项目里,大家肯定接触过axios库,一个易用.简洁且高效,使用Promise管理异步,告别传统callback方式的http库. 最近有个项目里接口调取的频率比较高,接口队列长,然后等待 ...
最新文章
- iOS 修改搜索框的样式为白色
- 融合通信常见问题2月刊 | 云信小课堂
- python可以在linux运行_服务器(Linux)上运行python总结
- WinSock API相关函数
- decimal简单问题
- java monitor 翻译_Java 对象锁与monitor的区别
- 全局唯一编码ID生成器
- 面试中问到fiddler的那些问题
- 使用阿里iconfont unicode格式图标
- 使用vue-ui可视化管理工具来创建项目并安装vue-cli-plugin-element插件
- c语言编写好的程序运行自动退出,VS 2015 写的第一个c语言控制台程序,运行完程序就自动...
- 11 综合应用案例 :“搬家具”
- Swing-右键菜单
- 操作系统简介及编程语言
- 达芬奇密码 第八十二章
- Mac下安装keras
- 网上书店信息管理系统--基于Mysql数据库与java
- 阿里云一键登录(对接移动端) PHP
- 【VSCode】from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported
- Django 新建自定义用户后无法创建表的问题
热门文章
- 【USACO】贪婪的礼物送礼者
- Servlet图书管理系统测试报告
- JAVA SE 入门视频
- lonza原代细胞、培养基目录
- 第13期 《锲而不舍,金石可镂》11月刊
- Nginx windows 版本 修改句柄数 解决 maximum number of descriptors supported by select() is 1024 while waiting
- WPF Textbox自动换行
- 你真的会使用XMLHttpRequest吗? 1
- 微信小程序实现展开/收起的效果
- html5 canvas绘制树叶,使用HTML5 Canvas绘制毕达哥拉斯树