When caching async results, ensure stale responses can’t overwrite fresh data, and only refetch when the cached value’s lifecycle actually changes.
Rules
Pattern (simplified)
const generations = new Map<string, number>();
const cache = new Map<string, { data: string; generation: number }>();
function invalidate(key: string) {
generations.set(key, (generations.get(key) ?? 0) + 1);
cache.delete(key);
}
async function read(key: string, fetcher: () => Promise<string>) {
const gen = generations.get(key) ?? 0;
const data = await fetcher();
// Apply only if still current
if ((generations.get(key) ?? 0) !== gen) return;
cache.set(key, { data, generation: gen });
return data;
}
If you follow this, you prevent cache-related race conditions (stale async results winning) and avoid unnecessary reloads that waste work or reintroduce inconsistencies.