Function argument types
Function return type (unwrapped from Promise)
Key type (defaults to string)
Wrapped function with in-flight deduplication
// Basic usage - database query deduplication
const fetchUser = async (id: string) => db.users.findById(id);
const getUser = withInflightDedup(fetchUser);
// Three concurrent calls → one database query
const [user1, user2, user3] = await Promise.all([
getUser("42"),
getUser("42"),
getUser("42")
]);
// With hooks for observability
const search = async (q: string) => api.search(q);
const dedupedSearch = withInflightDedup(search, {
onStart: (k) => logger.debug("search started", k),
onJoin: (k) => logger.debug("joined existing search", k),
onResolve: (k) => logger.debug("search completed", k),
onReject: (k, e) => logger.error("search failed", k, e),
});
// Custom key - ignore volatile parameters
const fetchData = async (id: string, opts: { timestamp?: number }) => { };
const dedupedFetch = withInflightDedup(fetchData, {
generateKey: (id) => id // Only dedupe by id, ignore opts
});
// Hot path optimization - extract discriminating field only
const getProfile = async (req: { userId: string; meta: LargeObject }) => { };
const dedupedGetProfile = withInflightDedup(getProfile, {
generateKey: (req) => req.userId // Avoid serializing large meta object
});
// Functions as arguments - MUST use custom generateKey
const fetchWithTransform = async (url: string, transform: (data: any) => any) => { };
const dedupedFetch = withInflightDedup(fetchWithTransform, {
generateKey: (url) => url // Only dedupe by URL, ignore transform function
});
// Conditional deduplication - bypass for cache-busting requests
const fetchData = async (url: string, opts?: { bustCache?: boolean }) => { };
const smartFetch = withInflightDedup(fetchData, {
shouldDedupe: (url, opts) => !opts?.bustCache
});
// These two calls are deduped
await Promise.all([
smartFetch('/api/data'),
smartFetch('/api/data')
]);
// This call bypasses deduplication and executes directly
await smartFetch('/api/data', { bustCache: true });
Wrap an async function so concurrent calls with the same key share the same in-flight promise.
What it does:
What it doesn't do:
memoizefor that)When to use:
Performance notes:
keyFnto extract only discriminating fieldskeyFn(functions always collide in default serializer)