Skip to main content

Memoize Function

Performance4 functions

Utility Overview

Details

Caches function results to avoid expensive recalculations, improving performance for pure functions with predictable inputs

Category:Performance
Functions:memoize, memoizeLRU, memoizeTTL, memoizeSimple
Performance:

- Time: O(1) for cache hits, O(f) for original function execution - Space: O(n) where n is number of unique input combinations cached

Concepts:
closurescachingperformance optimizationpure functions

Implementation

memoize

Time: O(1) | Space: O(n)
export function memoize<Args extends unknown[], Return>(
  fn: (...args: Args) => Return,
  keyGenerator?: (...args: Args) => string
): (...args: Args) => Return {
  if (typeof fn !== 'function') throw new Error("First argument must be a function");
  
  const cache = new Map<string, Return>();
  
  const generateKey = keyGenerator || ((...args: Args) => JSON.stringify(args));
  
  return (...args: Args): Return => {
    const key = generateKey(...args);
    
    if (cache.has(key)) {
      return cache.get(key)!;
    }
    
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

// Memoize with LRU cache to prevent memory leaks

Usage Examples

Recursive function optimization

const fibonacci = (n: number): number => {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

const memoizedFib = memoize(fibonacci);

// Without memoization: ~1.5 seconds
// With memoization: ~1 millisecond
console.time('memoized');
memoizedFib(40); // 102334155
console.timeEnd('memoized');

API response caching with TTL

const fetchUsers = async (endpoint: string) => {
  const response = await fetch(`/api/${endpoint}`);
  return response.json();
};

const cachedFetch = memoizeTTL(fetchUsers, 60000); // 1 minute cache

// First call: makes HTTP request
await cachedFetch('users');

// Subsequent calls within 1 minute: returns cached data
await cachedFetch('users'); // No HTTP request made

LRU cache for memory management

const processLargeDataset = (data: unknown[]) => {
  // Expensive computation
  return data.reduce((acc, item) => 
    acc + complexCalculation(item), 0);
};

const memoizedProcess = memoizeLRU(processLargeDataset, 50);

// Only keeps 50 most recent results in memory
for (let i = 0; i < 100; i++) {
  memoizedProcess(generateData(i));
}
// Memory usage stays constant

Simple memoization for single arguments

const expensiveHash = (input: string) => {
  // Simulate expensive hashing operation
  let hash = 0;
  for (let i = 0; i < input.length * 1000; i++) {
    hash = ((hash << 5) - hash + input.charCodeAt(i % input.length)) & 0xffffffff;
  }
  return hash.toString(16);
};

const memoizedHash = memoizeSimple(expensiveHash);

// First call: performs expensive calculation
memoizedHash('password123'); // Takes time

// Subsequent calls: instant return
memoizedHash('password123'); // Instant