axios如何取消重复无用的请求详解
前言
在开发中,经常会遇到接口重复请求导致的各种问题。
对于重复的get请求,会导致页面更新多次,发生页面抖动的现象,影响用户体验。
对于重复的post请求,会导致在服务端生成两次记录(例如生成两条订单记录)。
如果当前页面请求还未响应完成,就切换到了下一个路由,那么这些请求直到响应返回才会中止。
无论从用户体验或者从业务严谨方面来说,取消无用的请求确实是需要避免的。
当然我们可以通过页面loading来避免用户进行下一次的操作,但本文只讨论单纯的如何取消这些无用的请求。
axios的cancelToken
axios是一个主流的http请求库,它提供了两种取消请求的方式。
通过axios.CancelToken.source生成取消令牌token和取消方法cancel
constCancelToken=axios.CancelToken; constsource=CancelToken.source(); axios.get('/user/12345',{ cancelToken:source.token }).catch(function(thrown){ if(axios.isCancel(thrown)){ console.log('Requestcanceled',thrown.message); }else{ //handleerror } }); axios.post('/user/12345',{ name:'newname' },{ cancelToken:source.token }) //canceltherequest(themessageparameterisoptional) source.cancel('Operationcanceledbytheuser.');
通过axios.CancelToken构造函数生成取消函数
constCancelToken=axios.CancelToken; letcancel; axios.get('/user/12345',{ cancelToken:newCancelToken(functionexecutor(c){ //Anexecutorfunctionreceivesacancelfunctionasaparameter cancel=c; }) }); //canceltherequest cancel();
需要注意的是在catch中捕获异常时,应该使用axios.isCancel()判断当前请求是否是主动取消的,以此来区分普通的异常逻辑。
封装取消请求逻辑
上面有两种取消请求,用哪种都是可以的,这里使用第二种。
取消请求主要有两个场景:
- 当请求方式method,请求路径url,请求参数(get为params,post为data)都相同时,可以视为同一个请求发送了多次,需要取消之前的请求
- 当路由切换时,需要取消上个路由中未完成的请求
我们封装几个方法:
//声明一个Map用于存储每个请求的标识和取消函数 constpending=newMap() /** *添加请求 *@param{Object}config */ constaddPending=(config)=>{ consturl=[ config.method, config.url, qs.stringify(config.params), qs.stringify(config.data) ].join('&') config.cancelToken=config.cancelToken||newaxios.CancelToken(cancel=>{ if(!pending.has(url)){//如果pending中不存在当前请求,则添加进去 pending.set(url,cancel) } }) } /** *移除请求 *@param{Object}config */ constremovePending=(config)=>{ consturl=[ config.method, config.url, qs.stringify(config.params), qs.stringify(config.data) ].join('&') if(pending.has(url)){//如果在pending中存在当前请求标识,需要取消当前请求,并且移除 constcancel=pending.get(url) cancel(url) pending.delete(url) } } /** *清空pending中的请求(在路由跳转时调用) */ exportconstclearPending=()=>{ for(const[url,cancel]ofpending){ cancel(url) } pending.clear() }
Map是ES6中一种新型的数据结构,本身提供了诸多方法,方便操作,适合当前场景。如果不熟悉的可以查看ECMAScript6入门。
在给config.cancelToken赋值的时候,需要判断当前请求是否已经在业务代码中使用了cancelToken
qs是一个专门用来转换对象和字符串参数的库,最初是由TJ创建并维护的,也是axios推荐使用的参数序列化库。这里我们的目的只是单纯的将参数对象转换为字符串方便拼接。
Map结构默认部署了Symbol.iterator属性,可以使用for...of循环直接获取键名和键值,当然你也可以使用for...in循环。
在axios拦截器中使用
主要的方法已经写好了,只需要添加到axios拦截器中就可以了。
axios.interceptors.request.use(config=>{ removePending(options)//在请求开始前,对之前的请求做检查取消操作 addPending(options)//将当前请求添加到pending中 //othercodebeforerequest returnconfig },error=>{ returnPromise.reject(error) }) axios.interceptors.response.use(response=>{ removePending(response)//在请求结束后,移除本次请求 returnresponse },error=>{ if(axios.isCancel(error)){ console.log('repeatedrequest:'+error.message) }else{ //handleerrorcode } returnPromise.reject(error) })
将clearPending()方法添加到vue路由钩子函数中
router.beforeEach((to,from,next)=>{ clearPending() //... next() })
测试效果
最后我们可以在浏览器中测试下,可以将chrome中控制面板的Network的网络状态切换为Slow3G来模拟网速慢的情况。
我们把查询按钮的loading或者disabled属性干掉来方便测试
在上面控制面板中可以看到,红色的status为canceled的就是被取消的请求。
上面代码在e-admin-vue(一个使用vue+element-ui+vue-cli3构建的rbac权限模型)或者e-admin-react(一个使用react+antd+create-react-app构建的rbac权限模型)中都有体现,欢迎star。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。