axios 之cancelToken原理以及使用
axios 之cancelToken原理以及使用
cancelToken
在真实项目中,当路由已经跳转,而上一页的请求还在pending状态,如果数据量小还好,数据量大时,跳到新页面,旧的请求依旧没有停止,这将会十分损耗性能,这时我们应该先取消掉之前还没有获得相应的请求,再跳转页面。这里axios给我们提供了一个方法:
cancelToken其实就是用来取消ajax请求
基本用法
//切换页面取消请求
let source = axios.CancelToken.source();
axios.interceptors.request.use((request) => {
request.cancelToken = source.token;
return request;
});
router.then((lib) => {
lib.default.beforeEach((to, from, next) => {
source.cancel();
source = axios.CancelToken.source();
next();
});
})
取消请求之后,会进入error,在里面处理一下如果是取消请求,就不报错,
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (axios.isCancel(error)) {
console.log( 'request cancel ', JSON.stringify(error))
return new Promise(() =>{})
}
return Promise.reject(error)
})
实现原理
promise只有三种状态,pending(等待),resolved(成功),rejected(失败)。
它的本质就是在解决如何取消一个已经执行的promise本身。
源码部分
function Cancel(message) {
this.message = message; // 可以传递因何取消请求的message
}
function CancelToken(executor) {
// 判断executor是一个函数,不然就报错
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve; // 关键代码一
});
var token = this;
// 以上token现在有一个promise属性,是一个未成功的promise对象;
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason); //关键代码二: 把接收到的“取消请求信息”token.reason传递给下一个then中成功函数作为参数
});
}
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
// source 方法
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c; // 关键代码三:实现“在他处取消请求”,与上面“终止一个promise”异曲同工。
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
source()函数
source方法很简单,就是返回一个具有token和cancel属性的对象,但是token和cancel都是通过CancelToken这个构造函数来的,
token
souce.token是一个实例化对象,是一个未成功的promise对象;
cancel()函数
souce.cancel就是用来触发取消请求的函数。
cancel执行,给token加了一个reason属性,
Cancel特别简单就是给实例化对象添加一个message属性,所以现在token.reason是一个具有message属性的对象了。
cancelToken
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);