Memoization & Performance Optimization

📖 Concept

Memoization caches the results of expensive function calls and returns the cached result when the same inputs occur again.

It's an optimization technique that trades memory for speed — ideal for:

  • Pure functions (same inputs always give same output)
  • Expensive computations (recursive algorithms, complex calculations)
  • Repeated calls with the same arguments

🏠 Real-world analogy: Memoization is like a student who writes answers on a cheat sheet during open-book exams. Instead of looking up the same formula every time, they check their notes first. If they've solved it before, they reuse the answer.

💻 Code Example

codeTap to expand ⛶
1// Basic memoize
2function memoize(fn) {
3 const cache = new Map();
4 return function(...args) {
5 const key = JSON.stringify(args);
6 if (cache.has(key)) {
7 console.log("Cache hit!");
8 return cache.get(key);
9 }
10 const result = fn.apply(this, args);
11 cache.set(key, result);
12 return result;
13 };
14}
15
16// Fibonacci without memoization: O(2^n) 😱
17function fib(n) {
18 if (n <= 1) return n;
19 return fib(n - 1) + fib(n - 2);
20}
21
22// Fibonacci with memoization: O(n) 🚀
23const memoFib = memoize(function fib(n) {
24 if (n <= 1) return n;
25 return memoFib(n - 1) + memoFib(n - 2);
26});
27
28console.time("no-memo");
29fib(35); // ~100ms
30console.timeEnd("no-memo");
31
32console.time("memo");
33memoFib(35); // ~0.1ms
34console.timeEnd("memo");
35
36// Advanced memoize with LRU cache (limited size)
37function memoizeLRU(fn, maxSize = 100) {
38 const cache = new Map();
39 return function(...args) {
40 const key = JSON.stringify(args);
41 if (cache.has(key)) {
42 const value = cache.get(key);
43 cache.delete(key);
44 cache.set(key, value); // Move to end (most recent)
45 return value;
46 }
47 const result = fn.apply(this, args);
48 cache.set(key, result);
49 if (cache.size > maxSize) {
50 const firstKey = cache.keys().next().value;
51 cache.delete(firstKey); // Remove least recently used
52 }
53 return result;
54 };
55}
56
57// Performance measurement
58console.time("operation");
59// ... expensive operation
60console.timeEnd("operation");
61
62// Performance API
63const t0 = performance.now();
64// ... operation
65const t1 = performance.now();
66console.log(`Took ${(t1 - t0).toFixed(2)}ms`);

🏋️ Practice Exercise

Mini Exercise:

  1. Implement memoization for a factorial function and measure the speedup
  2. Build an LRU cache class with get, set, and delete methods
  3. Memoize a function that fetches user data by ID (async memoization)
  4. Write a benchmark utility that compares performance of two functions

⚠️ Common Mistakes

  • Memoizing impure functions — if the function has side effects or depends on external state, cached results may be wrong

  • Using unbounded caches — memory grows indefinitely! Use LRU or TTL-based eviction

  • Using JSON.stringify as cache key for objects with circular references — it throws

  • Memoizing functions with many unique inputs — cache rarely hits, just wastes memory

  • Not considering that memoization adds overhead — for cheap functions, the overhead exceeds savings

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Memoization & Performance Optimization. Login to unlock this feature.