Lesson 24 / 25

Trade-offs and Performance Pitfalls

Where FP style costs more than it gives.

Know the costs

Common pitfalls in JavaScript-style FP: long chains of map/filter allocate an intermediate array per step (usually fine; matters in hot paths over large data); spreading inside reduce copies the accumulator every iteration, turning linear work quadratic; deep copying whole state trees instead of path copying; recursion on unbounded input without tail-call optimisation; memoisation that leaks memory or keys on object identity. Readability costs matter too: heavy point-free code, unfamiliar abstractions (monad transformers, custom operators) and mismatched team conventions slow reviews. Measure with a profiler before optimising, and choose the style that your team can read.

Quadratic reduce and a linear fix

Both are pure from the caller's point of view.

type Item = { id: string; value: number };

// Quadratic: copies the growing object on every step
const indexSlow = (items: Item[]) =>
  items.reduce<Record<string, Item>>((acc, it) => ({ ...acc, [it.id]: it }), {});

// Linear: local mutation of a fresh object that never escapes half-built
function indexFast(items: Item[]): Record<string, Item> {
  const acc: Record<string, Item> = {};
  for (const it of items) acc[it.id] = it;
  return acc;
}

// Or use a built-in that does the same
const indexBuiltIn = (items: Item[]) =>
  Object.fromEntries(items.map(it => [it.id, it] as const));

Local mutation is fine

A function that mutates only objects it created itself, and returns them without exposing intermediate states, is still pure from the outside. Purity is about observable behaviour.

Quick check: Why can `reduce` with object spread on every step be slow?

  • Spread syntax runs network requests
  • reduce is not optimised by engines
  • It copies the whole accumulator each iteration, making the work quadratic
  • Objects cannot be returned from reduce
Answer

It copies the whole accumulator each iteration, making the work quadratic — Copying grows with the accumulator size.