Skip to content

Commit

Permalink
feat(优化): 调整cache配置,让其部分参数可以全局配置
Browse files Browse the repository at this point in the history
  • Loading branch information
mengxinssfd committed Apr 23, 2022
1 parent cc516f1 commit 0c3099e
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 37 deletions.
71 changes: 57 additions & 14 deletions __test__/AxiosRequestTemplate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,65 @@ describe('AxiosWrapper', () => {
expect(e).toEqual({ code: 0, msg: '账号或密码错误' });
}
});
test('no cache', async () => {
const res = await get<{ username: string; id: number }>('/user');
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user');
expect(res2).toEqual(res);
expect(res2).not.toBe(res);
});
test('cache', async () => {
const res = await get<{ username: string; id: number }>('/user', undefined, { useCache: true });
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user', undefined, {
useCache: { timeout: 1000 },

describe('AxiosWrapper Cache', () => {
test('no cache', async () => {
const res = await get<{ username: string; id: number }>('/user');
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user');
expect(res2).toEqual(res);
expect(res2).not.toBe(res);
});
test('cache', async () => {
const res = await get<{ username: string; id: number }>('/user', undefined, { cache: true });
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user', undefined, {
cache: { timeout: 1000 },
});
expect(res2).toEqual(res);
expect(res2).toBe(res);
});
test('global cache object', async () => {
const req = new AxiosRequestTemplate({}, { cache: {} });
const get = req.methodFactory('get');
const res = await get<{ username: string; id: number }>('/user');
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user');
expect(res2).toEqual(res);
expect(res2).toBe(res);
});
test('global cache empty object', async () => {
const req = new AxiosRequestTemplate<CustomConfig>({}, { cache: true });
const get = req.methodFactory('get');
const res = await get<{ username: string; id: number }>('/user');
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user');
expect(res2).toEqual(res);
expect(res2).toBe(res);

const res3 = await get<{ username: string; id: number }>('/user', {}, { cache: false });
expect(res3).toEqual(res);
expect(res3).not.toBe(res);
});
test('global cache empty object', async () => {
const req = new AxiosRequestTemplate<CustomConfig>(
{},
{ cache: { enable: false, timeout: 1000 * 60 } },
);
const get = req.methodFactory('get');
const res = await get<{ username: string; id: number }>('/user');
expect(res).toEqual({ code: 200, data: { username: 'get', id: 1 }, msg: 'success' });
const res2 = await get<{ username: string; id: number }>('/user', {}, { cache: true });
expect(res2).toEqual(res);
expect(res2).not.toBe(res);

const res3 = await get<{ username: string; id: number }>('/user', {}, { cache: true });
expect(res3).toEqual(res);
expect(res3).not.toBe(res);
expect(res3).toBe(res2);
});
expect(res2).toEqual(res);
expect(res2).toBe(res);
});

test('serve 404', async () => {
try {
await get('/test');
Expand Down
72 changes: 50 additions & 22 deletions src/AxiosRequestTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import axios, {
} from 'axios';
import Qs from 'qs';
import { Cache } from './Cache';
import { CustomCacheConfig } from './types';

const root = Function('return this')();

Expand All @@ -19,10 +20,9 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
protected axiosIns!: AxiosInstance;
protected cache!: Cache<AxiosRequestConfig, AxiosPromise>;
protected readonly cancelerMap = new Map<CancelToken, Canceler>();
protected readonly tagMap = new Map<string, CancelToken[]>();
protected readonly tagCancelMap = new Map<string, CancelToken[]>();

cancelCurrentRequest?: Canceler;
protected clearCurrentRequestCB?: Function;

constructor(
private globalRequestConfig: AxiosRequestConfig = {},
Expand Down Expand Up @@ -67,33 +67,40 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
// });
}

protected handleCanceler(requestConfig: AxiosRequestConfig, customConfig: CustomConfig) {
// 设置取消handler
protected handleCanceler(
requestConfig: AxiosRequestConfig,
customConfig: CustomConfig,
): Function {
const { cancel, token } = axios.CancelToken.source();
requestConfig.cancelToken = token;
const tag = customConfig.tag;

// 缓存取消函数
// 缓存tag取消
if (tag) {
if (!this.tagMap.has(tag)) {
this.tagMap.set(tag, []);
if (!this.tagCancelMap.has(tag)) {
this.tagCancelMap.set(tag, []);
}
(this.tagMap.get(tag) as CancelToken[]).push(token);
(this.tagCancelMap.get(tag) as CancelToken[]).push(token);
}

// 缓存取消
this.cancelerMap.set(token, cancel);
// 请求成功后去除取消函数
this.clearCurrentRequestCB = () => {
// 清理取消
const clearCanceler = () => {
this.cancelerMap.delete(token);
if (!tag) return;
const tokens = this.tagMap.get(tag);
const tokens = this.tagCancelMap.get(tag);
if (!tokens || !tokens.length) return;
const index = tokens.indexOf(token);
tokens.splice(index, 1);
};
// 取消
this.cancelCurrentRequest = (msg) => {
cancel(msg);
this.clearCurrentRequestCB?.();
clearCanceler();
};
requestConfig.cancelToken = token;
return clearCanceler;
}
// 处理requestConfig
protected handleRequestConfig(
Expand All @@ -104,13 +111,33 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
finalConfig.method = finalConfig.method || 'get';
return finalConfig;
}
// 合并缓存配置
protected mergeCacheConfig(cacheConfig: CustomConfig['cache']): CustomCacheConfig {
function merge(cache: CustomConfig['cache'], base: CustomCacheConfig = {}) {
switch (typeof cache) {
case 'boolean':
base.enable = cache;
break;
case 'object':
base = { ...base, ...cache };
if (cache.enable === undefined) {
base.enable = true;
}
break;
}
return base;
}
return merge(cacheConfig, merge(this.globalCustomConfig.cache));
}
// 处理CustomConfig
protected handleCustomConfig(customConfig: CC) {
return { ...this.globalCustomConfig, ...customConfig };
const config = { ...this.globalCustomConfig, ...customConfig };
config.cache = this.mergeCacheConfig(customConfig.cache);
return config;
}
// 处理请求的数据
protected handleRequestData(data: {}, requestConfig: AxiosRequestConfig) {
if (requestConfig.method === 'get') {
if (String(requestConfig.method).toLowerCase() === 'get') {
requestConfig.params = data;
return;
}
Expand Down Expand Up @@ -141,9 +168,10 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
}

// 请求
protected async doRequest(requestConfig: AxiosRequestConfig, customConfig: CC) {
protected doRequest(requestConfig: AxiosRequestConfig, customConfig: CC) {
// 使用缓存
const useCache = customConfig.useCache;
const cacheConfig = customConfig.cache as CustomCacheConfig;
const useCache = cacheConfig.enable;
if (useCache) {
const cache = this.cache.get(requestConfig);
if (cache) return cache;
Expand Down Expand Up @@ -177,21 +205,21 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
// 1、处理配置
requestConfig = this.handleRequestConfig(url, requestConfig);
customConfig = this.handleCustomConfig(customConfig);
this.handleCanceler(requestConfig, customConfig);
const clearCanceler = this.handleCanceler(requestConfig, customConfig);
// 2、处理参数
this.handleRequestData(data, requestConfig);
try {
// 3、请求
const response: AxiosResponse = await this.doRequest(requestConfig, customConfig);
// 清理cancel
this.clearCurrentRequestCB?.();
clearCanceler();
// 4、请求结果数据结构处理
const data = this.transformRes<T>(requestConfig, customConfig, response);
// 5、状态码处理,并返回结果
return this.handleResponse<T>(response, data, customConfig);
} catch (e: any) {
// 清理cancel
this.clearCurrentRequestCB?.();
clearCanceler();
// 错误处理
const response: AxiosResponse<ResType<any>> = e.response;
// 4、请求结果数据结构处理
Expand All @@ -209,18 +237,18 @@ export class AxiosRequestTemplate<CC extends CustomConfig = CustomConfig> {
cancelAll(msg?: string) {
this.cancelerMap.forEach((canceler) => canceler(msg));
this.cancelerMap.clear();
this.tagMap.clear();
this.tagCancelMap.clear();
}

// 根据tag标签取消请求
cancelWithTag(tag: string, msg?: string) {
const tokens = this.tagMap.get(tag);
const tokens = this.tagCancelMap.get(tag);
if (!tokens) return;
tokens.forEach((token) => {
this.cancelerMap.get(token)?.(msg);
this.cancelerMap.delete(token);
});
this.tagMap.delete(tag);
this.tagCancelMap.delete(tag);
}

// 简单工厂:生成get post delete等method
Expand Down
8 changes: 7 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ export type StatusHandlers<CC extends CustomConfig = CustomConfig> = Record<
number,
StatusHandler<CC>
> & { default?: StatusHandler<CC> };

export interface CustomCacheConfig {
enable?: boolean;
timeout?: number;
}

// CustomConfig
export interface CustomConfig {
returnRes?: boolean; // 返回res
silent?: boolean; // 报错不弹窗
statusHandlers?: StatusHandlers;
useCache?: boolean | { timeout: number };
cache?: boolean | CustomCacheConfig;
tag?: string;
}

Expand Down

0 comments on commit 0c3099e

Please sign in to comment.