Axios取消请求以及其原理(v0.26.1)
Axios取消请求以及其原理(v0.26.1)
1. 取消请求
const axios = require('axios')
const instance = new axios.Axios({})
// 创建source,通过source.cancel()取消请求
const source = new axios.CancelToken.source()
instance.defaults.timeout = 10000
instance.interceptors.request.use(
config => {
config.cancelToken = source.token
return config
}
)
// 此处写了两个响应拦截器是测试用,
// 因为我在项目中看到他人
// 定义了一个全局的CancelToken.source。当请求失败
// 报错后执行source(),使config.token.reason.message = undefined
// dispatchRequest时会调用CancelToken.prototype.throwIfRequested方法,
// 直接抛出异常信息config.token.reason,不发送ajax请求
instance.interceptors.response.use(
({ data, status, statusText }) => {
if (status < 200 || status > 399) {
throw statusText
}
return data
}
)
instance.interceptors.response.use(
undefined,
error => {
// 取消请求
source.cancel()
throw error
}
)
2. 取消请求的原理
调用 CancelToken.source.cancel方法 时,将 CancelToken实例 上的 promise 属性的状态改为 fulfilled
CancelToken.source方法
CancelToken.source = function source() {
var cancel;
// 用cancel保存executor中的方法c方法,执行cancel()时,会将token.promise的状态变为fulfilled
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
CancelToken构造函数
function CancelToken(executor) {
// 此处省略executor须为function类型的校验
// 用resolvePromise保存Promise中的resolve方法,在执行source.cancel()的时候调用
var resolvePromise;
this.promise = new Promise((resolve) => {
resolvePromise = resolve;
});
var token = this;
// promise的状态变为fulfilled时,遍历_listeners并执行里面的回调
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;
});
// 重写promise.then方法
// 若已取消请求,会在token.subscribe方法中执行resolve(this.reason)
this.promise.then = function(onfulfilled) {
var _resolve;
// eslint-disable-next-line func-names
var promise = new Promise(function(resolve) {
token.subscribe(resolve);
_resolve = resolve;
}).then(onfulfilled);
// 取消订阅
promise.cancel = function reject() {
token.unsubscribe(_resolve);
};
return promise;
};
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new CanceledError(message);
// 改变token.promise的状态为fulfilled
resolvePromise(token.reason);
});
}
CancelToken.prototype.subscribe方法
/**
* 利用发布订阅者模式,收集回调(执行xhr.abort方法)
*/
CancelToken.prototype.subscribe = function subscribe(listener) {
// 如果有reason,说明请求已取消,立即执行listener
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
};
明白以上逻辑后,剩下要做的就是订阅 xhr.abort方法 。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析