方式一ios
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
}
});
source.cancel('Operation canceled by the user.');
复制代码
方式二axios
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
cancel();
复制代码
在axios/lib/axios.js
中定义了跟取消相关的方法promise
var axios = createInstance(defaults);
...
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
...
复制代码
我先看CancelToken,进入到axios/lib/cancel/CancelToken.js
文件bash
function CancelToken(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;
//executor(cancel方法);
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
//token.reason是Cancel的实例
token.reason = new Cancel(message);
resolvePromise(token.reason);//改变promise的状态
});
}
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token, //CancelToken的实例
cancel: cancel //function cancel(message) {...}
};
};
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
复制代码
CancelToken构造函数,定义了一个promise,状态一直是padding,将决定状态的resolve方法传递cancel方法内部,cancel方法做为参数传到外部executor方法中。函数
CancelToken.source实际上new 一个CancelToken的实例,上述的cancel方法传给cancel变量源码分析
进入到axios/lib/cancel/Cancel.js
文件ui
function Cancel(message) {
this.message = message;
}
Cancel.prototype.toString = function toString() {
return 'Cancel' + (this.message ? ': ' + this.message : '');
};
Cancel.prototype.__CANCEL__ = true;
复制代码
Cancel构造函数,有属性message,Cancel.prototype有属性__CANCEL__this
进入到axios/lib/cancel/isCancel.js
文件spa
function isCancel(value) {
return !!(value && value.__CANCEL__);
};
复制代码
如何一步步实现取消的?prototype
function throwIfCancellationRequested(config) {
//判断是否配置有cancelToken,
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
}
function dispatchRequest(config) {
throwIfCancellationRequested(config);//请求前
...
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);//请求后,resolve
...
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) { //请求后,reject
throwIfCancellationRequested(config);
...
});
}
复制代码
调用throwIfCancellationRequested方法,内部实现先判断是否配置有cancelToken,则调用CancelToken.prototype.throwIfRequested,若是调用cancel操做过了确定reason存在,抛出throw reason,reason其实是Cancel的实例
在axios/lib/adapters/xhr.js
中
function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
...
if (config.cancelToken) {
//请求中,监听cancelToken中promise状态改变
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
request = null;
});
}
...
}
}
复制代码
总结: CancelToken.source().token实际可用理解为new 一个promise,状态一直是 padding。把可用改变状态方法传到cancel方法中。外部调用cancel实现取消请求。
cancel操做,实际上是执行resolvePromise,让cancelToken中promise状态变为已完成。实际上在发送请求前、请求中,请求后resolve、请求后reject四部分,都会去判断是否有cancel操做。