一般可用于优化本地请求多次
// util.ts
import addSeconds from 'date-fns/add_seconds';
import getTime from 'date-fns/get_time';
import request from './ajax'; // 自己封装好的request
/**
* 创建一个会缓存 func 结果的函数。 如果提供了 resolver ,就用 resolver 的返回值作为 key 缓存函数的结果。
* 默认情况下用第一个参数作为缓存的 key。 func 在调用时 this 会绑定在缓存函数上。相比 lodash-es 库,增加了异步函数的支持。
* @memberof module:shared
* @param {function} fn 需要缓存化的函数
* @param {function} opt 配置项 resolver: 生成 key , expire: 过期时间,以秒为单位
* @return {function} 包装后的函数
* @example
*
* const obj = { a: 1, b: 2 }
* const foo = (obj) => Object.values(obj)
* const bar = memorize(foo)
* bar(obj)
* // [1, 2]
* obj.a = 10
* bar(obj)
* // [1, 2]
*/
function isPromise(value: any): boolean {
return typeof value === 'object' && value !== null && typeof value.then === 'function';
}
export interface IMemorizeOptions {
resolver?: (...value: any[]) => NonNullable<any>;
expire: number;
}
export function memorize(
fn: (...rest: any[]) => any,
opt: IMemorizeOptions = {
expire: 60
}
) {
const cache = new Map();
const { resolver: hash, expire } = opt;
function setExpire(time: number): number | null {
return typeof time === 'number' ? getTime(addSeconds(Date.now(), time)) : null;
}
/* eslint-disable no-nested-ternary */
function memoized(this: any, ...params: any[]) {
const key = typeof hash === 'function' ? hash(...params) : params[0];
const {
expire: curExpire,
value: memoizedValue,
shouldReturnPromise
}: {
expire?: number;
value?: any;
shouldReturnPromise?: boolean;
} = cache.get(key) || {};
// 过期数据
if (typeof curExpire === 'number' && Date.now() > curExpire) {
cache.delete(key);
}
if (cache.has(key)) {
return shouldReturnPromise ? Promise.resolve(memoizedValue) : memoizedValue;
}
const res = fn.apply(this, params);
if (isPromise(res)) {
return res.then(
(value: any) => {
cache.set(key, {
value,
expire: setExpire(expire),
shouldReturnPromise: true
});
return value;
},
(err: Error) => Promise.reject(err)
);
}
cache.set(key, {
value: res,
expire: setExpire(expire)
});
return res;
}
memoized.cache = cache;
return memoized;
}
export function requestWithCache(options?: IMemorizeOptions) {
return memorize(request, options);
}
export default requestWithCache;
// 使用
function memoReq() {
return requestWithCache({
resolver: (url: string, params?: any) => `${url}_${JSON.stringify(params)}`,
expire: 60 * 10
});
}
const cacheReq = memoReq();
// apply:
cacheReq('/v1/xxx.api').then().catch()