main
ts 29 lines 1.07 KB
Raw
1 export function expiringCache<T, K=string>(ttlMs: number) {
2 if (!ttlMs)
3 throw Error('invalid TTL')
4 const o = new Map<K,T>()
5 return Object.assign(o, {
6 invalidate,
7 // creator can return undefined if the value should not be cached
8 try(k: K, creator: (k: K) => T): T {
9 let ret = o.get(k)
10 if (ret === undefined) { // undefined = missing, as we don't accept this value in our cache
11 ret = creator(k)
12 if (ret !== undefined) {
13 o.set(k, ret)
14 Promise.resolve(ret).then(v => {
15 if (v === undefined) // even in a promise, we'll consider undefined as a request to cancel the caching
16 invalidate(k)
17 }, () => {}) // avoid js warning
18 .finally(() => setTimeout(() => invalidate(k), ttlMs)) // wait for async (in case) before starting the timer
19 }
20 }
21 return ret
22 },
23 })
24
25 function invalidate(k: K) {
26 o.delete(k)
27 }
28 }
29