。
有时候我们需要对一些请求做出拦截,不让继续请求。
情景:当同样的接口连续请求时,我们可以把前面的请求在还未响应时,切断。
今天发现有人将请求接口写在了循环里,并且实现了一个功能,很是窝火。因为我认为把接口放在循环里是不对的,说不出哪不对,它就是不对。
近期做了axios请求切断。导致了这个功能失效。
记录一下:如何在拦截器切断统一请求。
我们封装了request请求拦截器,所以在拦截器里实现切断就可以了。
// 取消还未完成的同请求 let pending = []; let cancelToken = axios.CancelToken; let removePending = config => { for (let p in pending) { if (pending[p].u === config.url + "&" + config.method) { //当前请求在数组中存在时执行函数体 pending[p].f(); //执行取消操作 pending.splice(p, 1); } } };
上面这段代码 先声明了 一个队列;然后定义一个取消请求的方法;
用队列中每一项的 u属性和 请求的url+method方法做对比,若两者一样,代表是统一个请求。然后执行f方法(切断请求)。再删除队列中的这一项。
什么时候,想队列中添加数据呢?
在,请求拦截器中:
removePending(config); config.cancelToken = new cancelToken(c => { // 这里的axios标识是用请求地址&请求方式拼接的字符串 pending.push({ u: config.url + "&" + config.method, f: c }); });
在每次请求拦截器中先执行一次拦截的方法,如果条件匹配,则取消请求。如果没有取消本次请求,则执行请求拦截器后面的逻辑。
紧接着是,给config对象加一个canceltoken对象。new cancelToken的回调函数的第一个参数c,就是切断请求的方法。
可见,队列中的每一项,记录了本次请求的一个u:uuid,用于识别本次请求的id。这里用url和请求方法拼接成的。有一个弊端是,如果两次请求的参数不一样,同样会识别成同一请求。解决方法是:1、指定一个属性,控制某些请求不切断,或在u属性上加上参数值,参数值不同,就不会识别成 同一请求。
为了测地拦截重复请求,我们可以在响应拦截器中同样执行一次切断方法:
removePending(response.config);
以上做法有什么好处?
当有很多方法并行请求时,对服务器会产生压力。如果能够取消相同的请求,就会减轻服务器压力。
axios的cancelToken原理是什么呢?
其实是用一个外部变量 接受住了promise的resolve方法。从而可以在外部控制promise的执行。resolve传递出一个值,比如是cancel时,执行ajax的abort方法。从而取消请求。
来一个外部控制promise的例子:
let outResolve,count = 0; let a = function (){ return new Promise(resolve => { outResolve = resolve; setTimeout(() => { outResolve("111") },5000); }) } a().then(res => { console.log(res);//正常5s后会返回结果,但是由于下面的方法,在第2s时,提前结束了promise }) let timer = setInterval(() => { count += 1; console.log(count); if(count == 2){//执行这个代码会在第二秒提前执行promise的resolve方法 outResolve("外部截断promise") clearInterval(timer) } }, 1000);
。
。