-
Notifications
You must be signed in to change notification settings - Fork 4
/
memoize.ts
67 lines (57 loc) · 1.7 KB
/
memoize.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import type { ThenReturn } from '../type';
import type { AnyPromiseFN } from './type';
export type MemoizeReturnType<T extends AnyPromiseFN> = {
reset(...args: Parameters<T>): void;
clear(): void;
} & T;
/**
* 缓存promise结果,支持超时时间
* @param fn 被代理的异步函数
* @param harsher 返回标示本次运行结果的key
* @param timeoutMs
* @category Promise
*/
function memoize<FnType extends AnyPromiseFN>(
fn: FnType,
harsher: (...args: Parameters<FnType>) => any = (...args) => args[0],
timeoutMs?: number,
): MemoizeReturnType<FnType> {
const memos: Map<
ReturnType<typeof harsher>,
{ value: ThenReturn<FnType>; expiration: number }
> = new Map();
const queues: Map<ReturnType<typeof harsher>, Promise<ThenReturn<FnType>>> = new Map();
const returnFn = (async (...args: Parameters<FnType>): Promise<ThenReturn<FnType>> => {
const key = harsher(...args);
if (memos.has(key)) {
if (!timeoutMs || Date.now() < memos.get(key)!.expiration) {
return memos.get(key)!.value;
}
}
if (queues.has(key)) {
return await queues.get(key)!;
}
const promise = fn(...args);
queues.set(key, promise);
try {
const ret = await queues.get(key)!;
memos.set(key, { value: ret, expiration: Date.now() + (timeoutMs || 0) });
return ret;
} finally {
queues.delete(key);
}
}) as MemoizeReturnType<FnType>;
const reset = (...args: Parameters<FnType>): void => {
const key = harsher(...args);
if (memos.has(key)) {
memos.delete(key);
}
};
const clear = (): void => {
memos.clear();
};
returnFn.reset = reset;
returnFn.clear = clear;
return returnFn!;
}
export default memoize;