axios是一款基于xml和 http请求对象 封装的请求库, 本文梳理其请求中断逻辑
1. 中断函数的使用:
javascript
// 引入axios
const axios = require('axios');
// 创建取消令牌的源
const cancelTokenSource = axios.CancelToken.source();
// 发起一个请求
axios.get('https://example.com/api/data', {
cancelToken: cancelTokenSource.token
}).then(response => {
console.log('请求成功:', response.data);
}).catch(error => {
if (axios.isCancel(error)) {
console.log('请求被取消:', error.message);
} else {
// 处理其他错误
console.error('请求出错:', error);
}
});
// 如果需要取消请求
cancelTokenSource.cancel('取消请求,例如用户导航到其他页面');
2. cancelToken的source作用如下
javascript
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
new 出cancelToken的实例,定义executor函数,利用executor的形参获取到c, c为取消函数
3. cancelToken代码如下
javascript
// 文件路径 Axios/lib/cancel/CancelToken.js
// ...
/**
* A `CancelToken` is an object that can be used to request cancellation of an operation.
*
* @class
* @param {Function} executor The executor function.
*/
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
// 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;
});
// eslint-disable-next-line func-names
this.promise.then = function(onfulfilled) { // ...
};
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
// ...
cancelToken类会立即执行 executor函数,将取消方法作为实参传递, source中cancel接到的形参便是executor中的cancel实参, 外部执行cancel执行的是resolvePromise方法
javascript
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
resolvePromise 用于存放cancelToken类中promise的resolve, promise用于控制中断相关操作的执行。 当resolvePromise执行, promsie被放行,则会执行cancelToken中的listeners
javascript
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
javascript
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;
});
listenters是注册的中断函数,注册方法如下:
javascript
// 文件路径 Axios/lib/cancel/CancelToken.js
// ...
/**
* Subscribe to the cancel signal
*/
CancelToken.prototype.subscribe = function subscribe(listener) {
// reason 值不为 undefined 说明该请求已取消,可直接调用 listener
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
};
// ...
4. 核心请求方法
javascript
// Axios/lib/adapters/xhr.js
// ...
if (config.cancelToken || config.signal) {
// Handle cancellation
// eslint-disable-next-line func-names
onCanceled = function(cancel) {
if (!request) {
return;
}
reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
request.abort();
request = null;
};
config.cancelToken && config.cancelToken.subscribe(onCanceled);
if (config.signal) {
config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
}
}
// ...
在走请求流程时,如果当前请求配置有cnacelToken, 定义onCanceled 中断函数,并通过subscribe注册到cancelToken类中, 等待resolvePromise 放行promise, 从而执行中断逻辑。
总结
javascript
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
回顾一下source方法,
javascript
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
source返回了两个属性,
cancel是中断方法, 用于用户手动中断请求,
javascript
source.cancel('取消请求,例如用户导航到其他页面');
token为cancelToken实例, 显式的声明在axios请求上
javascript
axios.get('https://example.com/api/data', {
cancelToken: cancelTokenSource.token
}).then
当axios获取到cancelToken时,会定义中断请求的具体逻辑,通过cancelToken的 subscribe 进行订阅
cancelToken类本身存在一个promise, resolve方法被存放在变量中, 当手动触发cancel方法时, resolve会放行, promsie.then会执行先前订阅的中断逻辑。
而中断逻辑则是给当前请求的promsie一个reject, 并且手动abort网络请求
javascript
reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
request.abort();
request = null;