const CancelToken = axios.CancelToken;
// 1. 定义退出对象
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.');
通过 source.cancel
来触发取消请求,source 通过如下方法获得:
class CancelToken {
constructor(executor) {
//...
executor(function cancel(message, config, request) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new CanceledError(message, config, request);
resolvePromise(token.reason);
});
}
// ...
static source() {
let cancel;
const token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token,
cancel
};
}
}
cancel 是通过 new CancelToken 闭包的引用,其中的 c 便是 executor 的回调方法 cancel。
let resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
const token = this;
// eslint-disable-next-line func-names
this.promise.then(cancel => {
if (!token._listeners) return;
let i = token._listeners.length;
while (i-- > 0) {
token._listeners[i](cancel);
}
token._listeners = null;
});
在 executor 会调用 resolvePromise 从而逐步将 _listeners 调用取消,从而触发到 xhr.abort。
// lib\adapters\xhr.js
if (_config.cancelToken || _config.signal) {
// Handle cancellation
// eslint-disable-next-line func-names
onCanceled = cancel => {
if (!request) {
return;
}
reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);
request.abort();
request = null;
};
_config.cancelToken && _config.cancelToken.subscribe(onCanceled);
if (_config.signal) {
_config.signal.aborted ? onCanceled() : _config.signal.addEventListener('abort', onCanceled);
}
}
对比 AbortController 方式#
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
});
controller.abort();
- 更好的拥抱 web 标准
- 对比 cancelToken 操作更加便捷