Axios 新版本 CancelToken 已被 AbortController 替换
一、Axios CancelToken 应用
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
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
二、源码解析
- 先抛出 cancelToken 内部使用方法:
// lib/adapters/xhr.js 和 lib/adapters/http.js 都有类似代码:
// 取消事件监听
function done() {
if (config.cancelToken) {
config.cancelToken.unsubscribe(onCanceled);
}
}
// 监听中断事件
config.cancelToken && config.cancelToken.subscribe(onCanceled)
请求无论成功失败都会调用 done,可理解为:requestPromise().finally(done)
CancelToken源码解析注解:
class CancelToken {
constructor(executor) {
// 保证入参类型
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
// Promise 异步技巧,将 resolve 赋值给 resolvePromise,resolvePromise 执行则 Promise 状态改变
let resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
const token = this;
// resolvePromise 执行时,此处注册的 then 回调执行
this.promise.then(cancel => {
if (!token._listeners) return;
// 注册的事件监听器执行
let i = token._listeners.length;
while (i-- > 0) {
token._listeners[i](cancel);
}
token._listeners = null;
});
// 重写了 this.promise.then 方法,支持:`token.promise.then(onFulfilled)`
this.promise.then = onfulfilled => {
// 定义 _resolve 方便 subscribe 和 unsubscribe 使用
let _resolve;
const promise = new Promise(resolve => {
// resolve 作为 listener 被传入,监听中断事件
token.subscribe(resolve);
_resolve = resolve;
})
// 中断事件发生后执行 onfullfilled()
.then(onfulfilled);
// 支持取消监听
promise.cancel = function reject() {
token.unsubscribe(_resolve);
};
return promise;
};
// 通过 executor 将内部逻辑作为回调暴露给外部调用者,外部执行 cancel() 则推动此处逻辑进行
// 可结合类方法 source() 来理解
executor(function cancel(message, config, request) {
// 用户重复调用 cancel()
if (token.reason) {
return;
}
token.reason = new CanceledError(message, config, request);
// this.promise 得到解决,状态变更为 fulfilled
resolvePromise(token.reason);
});
}
/**
* 抛出 Error,用于请求过程中的检查
*/
throwIfRequested() {
if (this.reason) {
throw this.reason;
}
}
/**
* 订阅事件
*/
subscribe(listener) {
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
}
/**
* 取消事件订阅
*/
unsubscribe(listener) {
if (!this._listeners) {
return;
}
const index = this._listeners.indexOf(listener);
if (index !== -1) {
this._listeners.splice(index, 1);
}
}
/**
* 入口逻辑
*/
static source() {
let cancel;
// constructor 内将回调函数传递给 executor,进一步通过 cancel = c 暴露给外部调用者
// 调用 cancel() 则可以推动中断事件流程
const token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token,
cancel
};
}
}
参考内容
- AbortController
- abortcontroller-polyfill 对比学习,核心内容是:
dispatchEvent和Promise.race([fetch,eventHandlerPromise])