- Published on
axios的cancel功能源码解读
- Authors
- Name
- noodles
- 每个人的花期不同,不必在乎别人比你提前拥有
本文梳理axios中使用CancelToken来实现中断请求的源码实现. (CancelToken已经是deprecated, axios已支持AbortController实现相应的功能)
简单使用
const CancelToken = axios.CancelToken;
// 创建cancelToken
const source = CancelToken.source();
axios.get('/user/12345', {
// 请求的时候 传入创建的cancelToken
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
// 调用cancelToken的cancel方法 取消请求
source.cancel('Operation canceled by the user.');
上面是axios官网的上使用CancelToken的例子,可以看到通过将创建的cancelToken传入对应的请求对象,就实现了请求控制能力暴露给外部的能力。
源码分析
XMLHttpRequest支持使用abort方法实现请求的终止,axios底层封装了XMLHttpRequest来实现请求的处理,通过将调用abort方法的能力暴露给外部就实现了请求中断的控制。axios引入了cancelToken来实现这个过程的解耦。下面从具体的源码来看实现的过程
创建cancelToken对象
// 调用source方法 生成CancelToken 导出token和取消请求的cancel方法
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
// 设置CancelToken的promise函数
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
// cancel函数的执行逻辑 在调用cancel接口的时候 执行下面的逻辑
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
cancelToken与XMLHttpRequest绑定
// 代码是axios封装XMLHttpRequest的部分逻辑
if (config.cancelToken) {
// 如果传入的配置有cancelToken 就调用cancelToken的promise方法
// 通过promise实现控制流的流转 调用cancelToken方法的时候 将resolve时机暴露给cancelToken
// 调用cancelToken的cancel方法时,resolve了当前的promise,控制流程回到当前的后续流程,执行request.abort()从而完成请求的终止
config.cancelToken.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
if (!requestData) {
requestData = null;
}
// Send the request
request.send(requestData);
通过对实现流程的源码梳理,在类似的功能中可以利用promise来完成流程的控制。