const CancelToken = axios.CancelToken; //获得Cancel对象
const source = CancelToken.source(); //获得cancel的token对象以及cancel方法CancelToken.source源码,new 一个 CancelToken 对象,然后通过闭包获得内部 cancel 方法
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel,
};
};Axios 也支持
fetch API
const controller = new AbortController();
axios
.get('/foo/bar', {
signal: controller.signal,
})
.then(function (response) {
//...
});
// cancel the request
controller.abort();首先,闭包获得 Cancel 方法,给 executor 函数传入内部 cancal 方法
function CancelToken(executor) {
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new CanceledError(message);
resolvePromise(token.reason);
});
}所以自己可以这样实现
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
}),
});
// cancel the request
cancel();这样 cancel 变量就被赋值为取消函数。new CancelToken 返回值 token 是个 promise 对象,调用 cancel 后,token 状态会从 pending 变为 fullFilled,执行 fullFilled 回调即将 xhr 取消并且 reject。
在CancelToken内部维护一个 listener 队列,在 xhr 封装为 Promise 对象时,会将 onCancel 函数加入该队列
// xhr.js
onCanceled = function (cancel) {
if (!request) {
return;
}
reject(!cancel || (cancel && cancel.type) ? new CanceledError() : cancel);
request.abort();
request = null;
};
config.cancelToken && config.cancelToken.subscribe(onCanceled);
// 注意,在请求成功后,将onCancel从队列中移出
function done() {
if (config.cancelToken) {
config.cancelToken.unsubscribe(onCanceled);
}
if (config.signal) {
config.signal.removeEventListener('abort', onCanceled);
}
}在CancelToken.js中,将执行 listener 逻辑,放在 promise 的 then 调用中,一旦调用 cancel 函数,promise 的状态就会从 pending 转为 fullFilled,继而执行 listener 中的取消请求逻辑。
//CancelToken.js
// eslint-disable-next-line func-names
this.promise.then(function (cancel) {
if (!token._listeners) return;
var i;
var l = token._listeners.length;
for (i = 0; i < l; i++) {
token._listeners[i](cancel);
}
token._listeners = null;
});在dispatchRequest中,分别检查请求前,请求成功后,请求 reject 后是否含有config.cancelToken.reason对象,以及config.signal.aborted对象,如果有抛出CanceledError()错误,这样后续的 promise 链就会捕获到
module.exports = function dispatchRequest(config) {
// 请求前检查是否cancel
throwIfCancellationRequested(config);
//....
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(
function onAdapterResolution(response) {
// 请求成功时检查是否cancel
throwIfCancellationRequested(config);
return response;
},
function onAdapterRejection(reason) {
if (!isCancel(reason)) {
// 不是cancel的reject
throwIfCancellationRequested(config);
}
return Promise.reject(reason);
}
);
};AbortController对象,并将AbortController.signal加入config.signaldispatchRequest中,加入config.signal.addEventListener('abort', onCanceled),监听AbortController的abort行为AbortController是基于事件监听模式,而CancelToken也是类似的事件监听,但是使用promise的then调用,自动执行队列中的回调函数.