假如你熟悉 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 有必要取消吗,请求如何取消?相关推荐

  1. (Ajax)axios源码简析(三)——请求与取消请求

    传送门: axios源码简析(一)--axios入口文件 axios源码简析(二)--Axios类与拦截器 axios源码简析(三)--请求与取消请求 请求过程 在Axios.prototype.re ...

  2. axios取消接口请求

    自己碰到的问题,扒了很多文档才理清楚,当做是笔记记下来 说到取消接口请求,可能没碰到这样的坑冷不丁还有点懵,为什么会有取消请求这回事,既然决定要请求这个接口了又要取消它,岂不是有点画蛇添足的操作? 1 ...

  3. 关于 axios 取消重复请求的分析

    前言 关于取消重复请求,最重要的是这么做的意义,而不在于代码的实现 其实,我觉得,绝大部分能够想到的应用场景,都可以通过防抖.节流方式实现,比如实时搜索,比如重复订单提交.比如上拉获取最新数据等 我们 ...

  4. 输入框实时搜索优化,减少请求次数、取消无用请求

    背景 用户在输入框输入内容的同时进行搜索,针对搜索实时搜索结果进行展示 问题 如果不做处理,只监听输入框的input事件或者键盘按下弹起事件,实时对文本内容进行搜索,往往因为网络波动问题可能会造成结果 ...

  5. mvc ajax get请求,springMVC 中 ajax get 请求和 post 请求的坑以及参数传递

    1, ajax 请求 无论为 post ,或者 get ,url中带有?形式的参数,后台都能以String类型变量接收,变量名称和参数名称必须一致 前台ajax: $.ajax( "prod ...

  6. ASIHTTPRequest取消异步请求

    取消异步请求 首先,同步请求是不能取消的. 其次,不管是队列请求,还是简单的异步请求,全部调用[ request cancel ]来取消请求. 取消的请求默认都会按请求失败处理,并调用请求失败dele ...

  7. 注意ajax的同步和异步请求

    2019独角兽企业重金招聘Python工程师标准>>> 默认 一般ajax 或者 ajax工具  都是 异步请求的. 但是 在开发中,使用了一个 开源的 前端ui里面自带的ajax工 ...

  8. jQuery中ajax的4种常用请求方式

    jQuery中ajax的4种常用请求方式:1.$.ajax()返回其创建的 XMLHttpRequest 对象. $.ajax() 只有一个参数:参数 key/value 对象,包含各配置及回调函数信 ...

  9. 单页面axios_Axios封装之取消重复请求和接口缓存

    在平时的单页面项目里,大家肯定接触过axios库,一个易用.简洁且高效,使用Promise管理异步,告别传统callback方式的http库. 最近有个项目里接口调取的频率比较高,接口队列长,然后等待 ...

最新文章

  1. iOS 修改搜索框的样式为白色
  2. 融合通信常见问题2月刊 | 云信小课堂
  3. python可以在linux运行_服务器(Linux)上运行python总结
  4. WinSock API相关函数
  5. decimal简单问题
  6. java monitor 翻译_Java 对象锁与monitor的区别
  7. 全局唯一编码ID生成器
  8. 面试中问到fiddler的那些问题
  9. 使用阿里iconfont unicode格式图标
  10. 使用vue-ui可视化管理工具来创建项目并安装vue-cli-plugin-element插件
  11. c语言编写好的程序运行自动退出,VS 2015 写的第一个c语言控制台程序,运行完程序就自动...
  12. 11 综合应用案例 :“搬家具”
  13. Swing-右键菜单
  14. 操作系统简介及编程语言
  15. 达芬奇密码 第八十二章
  16. Mac下安装keras
  17. 网上书店信息管理系统--基于Mysql数据库与java
  18. 阿里云一键登录(对接移动端) PHP
  19. 【VSCode】from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported
  20. Django 新建自定义用户后无法创建表的问题

热门文章

  1. 【USACO】贪婪的礼物送礼者
  2. Servlet图书管理系统测试报告
  3. JAVA SE 入门视频
  4. lonza原代细胞、培养基目录
  5. 第13期 《锲而不舍,金石可镂》11月刊
  6. Nginx windows 版本 修改句柄数 解决 maximum number of descriptors supported by select() is 1024 while waiting
  7. WPF Textbox自动换行
  8. 你真的会使用XMLHttpRequest吗? 1
  9. 微信小程序实现展开/收起的效果
  10. html5 canvas绘制树叶,使用HTML5 Canvas绘制毕达哥拉斯树