mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-30 16:50:47 +08:00
Dedupe in-flight requests in cached()
The cache only stored resolved values, so callers asking for the same key while a request was still in flight each issued their own. The peer selector makes this easy to hit: Source and History render their own Header, so switching tabs while the remote listing loads fires a second copy of a request that takes seconds. Cache the promise instead, evicting it on rejection so failures still retry.
This commit is contained in:
+11
-10
@@ -3,19 +3,20 @@ import { LRUCache } from "lru-cache";
|
||||
export function cached<Args extends unknown[], V>(
|
||||
f: (...args: Args) => Promise<V>,
|
||||
makeKey: (...args: Args) => string,
|
||||
options?: LRUCache.Options<string, { value: V }, unknown>,
|
||||
options?: LRUCache.Options<string, { promise: Promise<V> }, unknown>,
|
||||
): (...args: Args) => Promise<V> {
|
||||
const cache = new LRUCache(options || { max: 500 });
|
||||
return async function (...args: Args): Promise<V> {
|
||||
return function (...args: Args): Promise<V> {
|
||||
const key = makeKey(...args);
|
||||
const cached = cache.get(key);
|
||||
const hit = cache.get(key);
|
||||
if (hit !== undefined) return hit.promise;
|
||||
|
||||
if (cached === undefined) {
|
||||
const value = await f(...args);
|
||||
cache.set(key, { value });
|
||||
return value;
|
||||
} else {
|
||||
return cached.value;
|
||||
}
|
||||
const promise = f(...args);
|
||||
// Evict on rejection so the next caller can retry with a fresh request.
|
||||
promise.catch(() => {
|
||||
cache.delete(key);
|
||||
});
|
||||
cache.set(key, { promise });
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user