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:
Rūdolfs Ošiņš
2026-07-29 16:21:23 +02:00
parent 16807eeeff
commit 3e500f8231
+11 -10
View File
@@ -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;
};
}