optimize(packages): Refactor axios request cancellation: replaced deprecated CancelToken with AbortController, added AbortSignal proxy.

This commit is contained in:
auooru 2024-07-06 11:35:45 +08:00
parent 531432d5ff
commit f50e883ec8

View File

@ -1,5 +1,5 @@
import axios, { AxiosError } from 'axios'; import axios, { AxiosError } from 'axios';
import type { AxiosResponse, CancelTokenSource, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios'; import type { AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';
import axiosRetry from 'axios-retry'; import axiosRetry from 'axios-retry';
import { nanoid } from '@sa/utils'; import { nanoid } from '@sa/utils';
import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options'; import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options';
@ -22,12 +22,28 @@ function createCommonRequest<ResponseData = any>(
const axiosConf = createAxiosConfig(axiosConfig); const axiosConf = createAxiosConfig(axiosConfig);
const instance = axios.create(axiosConf); const instance = axios.create(axiosConf);
const cancelTokenSourceMap = new Map<string, CancelTokenSource>(); const abortControllerMap = new Map<string, AbortController>();
// config axios retry // config axios retry
const retryOptions = createRetryOptions(axiosConf); const retryOptions = createRetryOptions(axiosConf);
axiosRetry(instance, retryOptions); axiosRetry(instance, retryOptions);
function configAbortSignal(requestId: string, config: InternalAxiosRequestConfig) {
const controller = new AbortController();
if (config.signal instanceof AbortSignal) {
// proxy abort signal
const originalSignal = config.signal;
originalSignal.addEventListener!('abort', e => {
controller.abort((e.target as AbortSignal).reason);
});
}
config.signal = controller.signal;
abortControllerMap.set(requestId, controller);
controller.signal.addEventListener('abort', () => {
abortControllerMap.has(requestId) && abortControllerMap.delete(requestId);
});
}
instance.interceptors.request.use(conf => { instance.interceptors.request.use(conf => {
const config: InternalAxiosRequestConfig = { ...conf }; const config: InternalAxiosRequestConfig = { ...conf };
@ -35,10 +51,8 @@ function createCommonRequest<ResponseData = any>(
const requestId = nanoid(); const requestId = nanoid();
config.headers.set(REQUEST_ID_KEY, requestId); config.headers.set(REQUEST_ID_KEY, requestId);
// config cancel token // config abort signal
const cancelTokenSource = axios.CancelToken.source(); configAbortSignal(requestId, config);
config.cancelToken = cancelTokenSource.token;
cancelTokenSourceMap.set(requestId, cancelTokenSource);
// handle config by hook // handle config by hook
const handledConfig = opts.onRequest?.(config) || config; const handledConfig = opts.onRequest?.(config) || config;
@ -79,18 +93,16 @@ function createCommonRequest<ResponseData = any>(
); );
function cancelRequest(requestId: string) { function cancelRequest(requestId: string) {
const cancelTokenSource = cancelTokenSourceMap.get(requestId); const cancelTokenSource = abortControllerMap.get(requestId);
if (cancelTokenSource) { if (cancelTokenSource) {
cancelTokenSource.cancel(); cancelTokenSource.abort('cancel request');
cancelTokenSourceMap.delete(requestId);
} }
} }
function cancelAllRequest() { function cancelAllRequest() {
cancelTokenSourceMap.forEach(cancelTokenSource => { abortControllerMap.forEach(cancelTokenSource => {
cancelTokenSource.cancel(); cancelTokenSource.abort('cancel all request');
}); });
cancelTokenSourceMap.clear();
} }
return { return {