Logos DX
    Preparing search index...

    Function withInflightDedup

    • Wrap an async function so concurrent calls with the same key share the same in-flight promise.

      What it does:

      • Deduplicates concurrent async calls with identical arguments (or custom key)
      • First call starts the producer; concurrent calls join the same promise
      • No caching after settlement - each new request starts fresh
      • Automatic cleanup on resolve/reject

      What it doesn't do:

      • No memoization/TTL/stale-while-revalidate (use memoize for that)
      • No AbortController handling (callers manage their own cancellation)
      • No request queuing (all concurrent calls share the same promise)

      When to use:

      • Deduplicating database queries that might be triggered multiple times
      • Preventing duplicate API calls during component re-renders
      • Sharing expensive computations across concurrent callers
      • Hot paths where multiple parts of code request the same resource

      Performance notes:

      • Default key generation: O(n) in argument structure size
      • For hot paths or complex args, use custom keyFn to extract only discriminating fields
      • For functions as arguments, MUST use custom keyFn (functions always collide in default serializer)

      Type Parameters

      • Args extends any[]

        Function argument types

      • Value

        Function return type (unwrapped from Promise)

      • Key = string

        Key type (defaults to string)

      Parameters

      Returns AsyncFunc<Args, Value>

      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 });