Axios 如何取消请求?

2023-01-06 0 1,000

应用领域情景

中止允诺在后端有时会加进,下列是三个组织工作中可能会加进的情景

tab转换时创下某一条目统计数据,假如她们相连接两个表达式储存统计数据条目,当允诺有延迟时间,可能会引致三个tab统计数据耗弱;求出文件格式或浏览文件格式时,中途中止 。

怎样中止允诺

中止http允诺,axios文件格式里提供更多了三种用语:

第二种:采用 CancelToken

const { CancelToken, isCanCel } = axios; constsource = CancelToken.source(); axios.get(/user/12345, { cancelToken: source.token }).catch(thrown => { if (isCancel(thrown)) { console.log(Request canceled, thrown.message); } else { // 处置其它极度 } }); axios.post(/user/12345, { name: new name }, { cancelToken: source.token }) / source.cancel(Operation canceled by the user.);

第三种:给构造表达式 CancelToken 传达两个 executor 表达式做为模块。此种方式的益处是,能用同一 cancel token 来中止数个允诺

constCancelToken = axios.CancelToken;let cancel; axios.get(/user/12345, { cancelToken: new CancelToken(function executor(c) { // 参数 c 也是个表达式 cancel = c; }) }); // 中止允诺,模块用语同上 cancel();

项目中用语示例

在两个真实的项目中,一般都会对axios进行二次封装,针对允诺、响应、状态码、code等做处置。贴两个项目里常用的request.js:

import axios from axios import store from @/store import { getToken } from @/utils/auth // 创建两个 axios 实例,并改变默认配置 const service = axios.create({ baseURL: process.env.BASE_API, // api 的 base_url timeout: 5000 // request timeout }) // 允诺拦截 service.interceptors.request.use( config => { // Do something before request is sent if (store.getters.token) { // 让每个允诺携带token– [X-Token]为自定义key 请根据实际情况自行修改 config.headers[X-Token] = getToken() } return config }, error => { // Do something with request error console.log(error) // for debug Promise.reject(error) } ) // 响应拦截service.interceptors.response.use(response => response, error => { alert(error) return Promise.reject(error) } ) export default service

对于某两个允诺添加中止的功能,要在调用api时,加上cancelToken选项,采用时的示例:

// api.js import request from request export function getUsers(page, options) { return request({ url: api/users, params: { page }, …options }) }// User.vue import { CancelToken, isCancel } from axios import { getUsers } from api… cancel:null … toCancel() { this.cancel(中止允诺) } getUsers(1, { cancelToken: newCancelToken(c => (this.cancel = c)) } ) .then(…) .catch(err => { if (isCancel) { console.log(err.message) }else { … } })

以上,我们就能顺顺利利地采用封装过的axios,中止某两个允诺了。其原理无非就是把cancelToken的配置项,在调用api时加上,然后就能在业务代码中止特定允诺了。

批量中止允诺

在 document 里的第三种方式已经说过:通过指定同一cancel token来中止。但是,在上面的项目示例中,不能控制拿到相同的cancel token。我们能换个思路:用数组保存每个需要中止的cancel token,然后逐一调用数组里的每一项即可:

// User.vue import{ CancelToken, isCancel }from axios import { getUsers } from api … cancel: [] … toCancel() { while (this.cancel.length >0) { this.cancel.pop()(中止允诺) } } getUser1(1, { cancelToken: newCancelToken(c1 => (this.cancel.push(c1))) } ) getUser2(2, { cancelTokem: new CancleTokem(c2 => (this.cancel.push(c2))) } )

转换路由时,中止允诺

上面讲了中止两个允诺及页面内批量abort的方式,此外,还有一种需求——转换路由时,中止所有。 这里不详细赘述了,大概思路就是在允诺拦截器里,统一加个token,并设置全局表达式source控制两个cancel token,在路由变化时调用cancel方式。

http.interceptors.request.use(config => { config.cancelToken = store.source.token return config }, err => { return Promise.reject(err) }) router.beforeEach((to, from, next) => { constCancelToken = axios.CancelToken store.source.cancel && store.source.cancel() store.source = CancelToken.source() next() })// 全局表达式store = { source: { token:null, cancel: null } }

中止允诺的实现原理

cancelToken的source方式维护了两个对象,里面包括了token令牌和cancel方式,token来自与缺省CancelToken,调用cancel方式后,token的promise状态为resolved,进而又调用了xhr的abort方式,取消允诺成功。 来分析下中止允诺是怎么实现的,先从两个简单的中止允诺的例子开始:

var CancelToken = axios.CancelToken; var source = CancelToken.source(); axios.get(/get?name=xmz, { cancelToken : source.token }).then((response)=>{ console.log(response, response) }).catch((error)=>{ if(axios.isCancel(error)){ console.log(中止允诺传递的消息, error.message) }else{ console.log(error, error) } }) // 中止允诺 source.cancel(中止允诺传达这条消息);

这就是两个简单的中止允诺的例子,那么就从最开始的axios.CancelToken来看,先去axios/lib/axios.js文件格式中。

axios.CancelToken= require(./cancel/CancelToken);

不费吹灰之力,就找到了CancelToken,在例子中我们调用了source方式,那么就去axios/lib/cancel/CancelToken.js文件中看看这个source方式到底是干什么的?

CancelToken.source = function(){ var cancel; var token = new CancelToken(function executor(c) { cancel = c }) return { token : token, cancel : cancel } }

source方式很简单,就是返回两个具有token和cancel属性的对象,但是token和cancel都是通过CancelToken这个缺省来的,那么还在这个文件格式中向上看,找到CancelToken表达式。

function CancelToken (executor){ // … // 判断executor是两个表达式,不然就报错 var resolvePromise; this.promise = new Promise(function(resolve){ resolvePromise = resolve; }) var token = this; // 以上token现在有两个promise属性,是两个未成功的promise对象;executor(function cancel(message){ if(token.reason){ return; } token.reason = newCancel(message); resolvePromise(token.reason); })// 这个cancel表达式就是 上面表达式中的cancel,也就是source.cancel; }

现在知道了source.cancel是两个表达式,souce.token是两个实例化对象,暂时就知道这些,继续看文章最开始的例子,接下来是去发送允诺了,最下面还有一行代码是执行souce.cancel();souce.cancel就是用来触发中止允诺的表达式。 现在再回头来看,上面的cancel表达式,cancel执行,给token加了两个reason属性,那么看下这个reason属性是什么吧,看下这个Cancel缺省,在axios/lib/cancel/Cancel.js文件格式中

function Cancel(message){ this.message = message }

Cancel特别简单就是给实例化对象添加两个message属性,所以现在token.reason是两个具有message属性的对象了。 继续回到cancel表达式中,resolvePromise表达式执行了,那么token.promise对象,这个原本未变成,成功状态的promise,变成了成功状态了,并且将token.reason对象传达过去了。 简单总结一下,执行中止表达式,就是让token的promise的状态变成了成功; 好了,突然发现分析中断了,变成成功状态又怎样了,怎么中止的呢?虽然现在的同步代码都执行完了,但是允诺还没发送出去呢,我们还要去看发送允诺的表达式

在分析发送允诺之前,再看下最开始的例子,和最普通的发送两个get允诺还是有一点区别的,配置对象中多了,两个cancelToken的属性,值是token,到底起了什么作用呢,去axios/lib/adapters/xhr.js中一探究竟(这里只截取其中关于cancelToken的部分)。

// 在发送允诺之前,验证了cancelToken,看来此处就是用来中止允诺的; if(config.cancelToken){ // 具体是怎样中止的,是在这个判断内定义的;config.cancelToken.promise.then(function(cancel){ request.abort(); reject(cancel); request = null; }) } // 发送允诺 request.send(requestData);

仔细看这只是两个promise的then表达式,只有在promise的状态变成成功后才会执行,而刚才我们分析了,cancel就是让这个promise的状态变成成功,所以假如执行了,中止允诺的表达式,这个then就会执行,中止发送允诺,并且把发送允诺的promise变成reject,被axiox.get().catch()捕获; 流程已经清楚了,最后再总结一下: 执行cancel是让token的promise变成成功,在真正发送允诺之前,验证token.promise的状态是否已经变了,假如变了,就中止允诺,就是这样两个简单的思想来进行中止允诺的。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务