通过AbortController取消请求
从v0.22.0版本开始,axios通过AbortController
来取消请求,之前通过CancelToken
来取消请求的方式已经被废弃,因此,我们只需要学习如何通过AbortController来取消请求即可。
AbortController的原理就是通过new AbortController()创建一个controller控制器对象,然后通过controller.signal监听abort事件,要取消请求时,执行controller.abort()即可。
// 创建一个abort controller
const controller = new AbortController();
// 监听abort信号,取消请求时会触发onCanceled回调
controller.signal.addEventListener('abort', onCanceled);
// 取消请求,会触发onCanceled回调
controller.abort()
实际使用axios取消请求,就是通过在配置中把controller.signal传递进去来实现的,下面是具体用法的例子:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
我们在adapters/xhr.js
文件来实现取消请求的具体逻辑。
var settle = require("../core/settle");
var parseHeaders = require("../helpers/parseHeaders");
var AxiosError = require('../core/AxiosError');
var CanceledError = require('../cancel/CanceledError');
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
//...
var onCanceled;
function done() {
if (config.signal) {
// 请求完成后,要取消监听abort事件
config.signal.removeEventListener('abort', onCanceled);
}
}
//...
// 取消请求的回调函数,调用 request.abort() 时触发
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
// 把request置为空
request = null;
};
// 如果配置中包含了signal,则在这里监听、触发取消请求事件
if (config.signal) {
onCanceled = function(cancel) {
if (!request) {
return;
}
// 这里不需要考虑cancelToken触发的取消,直接抛出CanceledError
reject(new CanceledError(null, config, req));
request.abort(); // 取消请求
request = null;
};
if (config.signal) {
// 如果用户已经触发controller.abort,则直接调用onCanceled回调来取消请求
// 否则监听abort事件,等待用户触发
config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
}
}
// ...
});
};
上面代码中我们用到了CanceledError
类来创建一个取消错误对象,取消操作时抛出该对象。该类就是对AxiosError类的一个封装,只不过把错误码指定为AxiosError.ERR_CANCELED,这是一种函数柯里化的小技巧。可以减少传参数量。
我们在根目录下创建cancel
目录,在该目录下创建CanceledError.js
文件,在该文件中实现CanceledError类
'use strict';
var AxiosError = require('../core/AxiosError');
var utils = require('../utils');
/**
* 取消操作时抛出的对象
*
* @class
* @param {string=} message 消息
* @param {Object=} config 配置
* @param {Object=} request XMLHttpRequest实例
*/
function CanceledError(message, config, request) {
AxiosError.call(this, message == null ? 'canceled' : message, AxiosError.ERR_CANCELED, config, request);
this.name = 'CanceledError';
}
// 继承AxiosError原型
utils.inherits(CanceledError, AxiosError, {
__CANCEL__: true
});
module.exports = CanceledError;
我们还需要一个isCancel
辅助函数帮助我们判断一个对象是否是CanceledError实例,我们继续在该目录下创建isCancel.js
文件,在该文件中实现辅助函数
module.exports = function isCancel(value) {
return !!(value && value.__CANCEL__);
};
我们在根目录的axios.js
中,对外提供这个辅助函数
axios.CanceledError = require('./cancel/CanceledError');
axios.isCancel = require('./cancel/isCancel');