receta
Memo

Patterns and Best Practices

Design patterns, anti-patterns, and performance optimization.

Best Practices

✅ Do: Memoize Pure Functions

// ✅ Good: Pure function
const double = memoize((n: number) => n * 2)

❌ Don't: Memoize Impure Functions

// ❌ Bad: Side effects
const log = memoize((msg: string) => {
  console.log(msg) // Side effect!
  return msg
})

✅ Do: Use Appropriate Cache Strategy

// Time-sensitive data: TTL
const weather = memoize(fetchWeather, { cache: ttlCache(5 * 60 * 1000) })

// Memory-limited: LRU
const user = memoize(fetchUser, { cache: lruCache(100) })

// Object keys: WeakMap
const process = memoizeBy(fn, x => x, { cache: weakCache() })

✅ Do: Invalidate on Mutations

const getUser = memoize(fetchUser)

async function updateUser(id: string, data: any) {
  await db.update(id, data)
  getUser.cache.delete(id) // Invalidate
}

Choosing Cache Strategy

Data TypeStrategyWhy
API responsesTTLAuto-refresh stale data
Database queriesLRULimit memory, keep hot data
ComputationsMapSimple, no expiration needed
DOM nodesWeakMapGC-friendly, no leaks

Debugging Cache Misses

const fn = memoize(expensive)

// Check if cached
console.log(fn.cache.has(key)) // false = cache miss

// Read the cached entry
console.log(fn.cache.get(key)) // Some(value), or None on a miss

The Cache interface has no size or iteration methods, so check entries by key.

Next Steps

On this page