Caching & Perf Budgets — Cheat Sheet

FE Lead prep · ref 08 · keep it fast FOREVER, not fast once

The frame — two enemies of speed

1. Repeated work → CACHE.   2. Silent regression & decay → BUDGETS + no memory leaks.

Caching stack (name the layer)

LayerCaches
Browser HTTPassets on disk — Cache-Control
CDN / edgeassets + HTML/API near user — s-maxage
App dataserver state in memory — React Query/SWR
(SW + Cache APIoffline — Lesson 20)

Cache-Control directives

The hashed-asset pattern (memorize)

app.a8f3c2.js  →  Cache-Control: max-age=31536000, immutable   // 1yr, hash = cache key
index.html     →  Cache-Control: no-cache                       // revalidate, pick up deploys
Hash in filename = cache key. Content changes → filename changes → fresh HTML points at new file. Aggressive caching + instant bust, zero stale-code risk.

App-level data cache (server state)

Perf budgets & guardrails (the systemic move)

BudgetExampleTool
Quantitybundle ≤170KB gz, ≤10 reqsize-limit
MilestoneLCP ≤2.5s, TBT ≤200msLighthouse CI
RuleLH Perf ≥90Lighthouse CI
Two-sided guardrail:  Pre-merge (lab): size-limit + Lighthouse CI fail the PR over budget.  Post-deploy (field): RUM web-vitals p75 LCP/INP/CLS dashboard + release alerts (lab can't catch real device/network/3rd-party variance).

Memory leaks (stay fast within a session)

SPA doesn't reload between routes → per-navigation leak compounds over a long session → slow then crash.
useEffect(()=>{
  const id=setInterval(poll,5000);
  window.addEventListener('resize',onResize);
  return ()=>{ clearInterval(id); window.removeEventListener('resize',onResize); }; // ← fix
},[]);

Lead one-liners (memorize)

Frame  “Fast once is easy; fast across 20 teams and a long session is the job — cache repeated work, budget regressions in CI, watch real users.”
Cache  “Content-hash assets, cache immutably for a year; HTML on no-cache. The hash is the cache key, so aggressive caching AND instant busting.”
Data  “Server state isn't UI state — React Query with stale-while-revalidate, dedupe, background refetch; force an authoritative read at checkout.”
Budget  “Regressions un-mergeable: size-limit + Lighthouse CI fail the PR; RUM p75 web-vitals catches what the lab can't, with release alerts.”
Leak  “SPAs don't reload, so a per-nav leak compounds — most are a missing teardown, so every subscribing effect unsubscribes; I confirm with comparison snapshots + the detached filter.”

Sources: web.dev — HTTP cache · MDN — Caching · web.dev — SWR · TanStack Query · web.dev — perf budgets · Lighthouse CI · Chrome — memory problems

Don't fail the interview

1. no-cache ≠ don't cache — it = store + revalidate each use. no-store = never store.
2. Hashed assets → max-age=31536000, immutable; HTML → no-cache. Hash = cache key = bust-on-deploy without stale code.
3. 304 saves the download, not the round trip. immutable skips even the RTT.
4. SWR = instant-but-stale → great for browseable lists, NOT checkout price/seats (force authoritative read).
5. React Query caches server state (dedupe/SWR/invalidate-on-mutation) — HTTP cache can't model shared mutating data.
6. Guardrail = two-sided: pre-merge CI gate (fail the PR) + post-deploy RUM p75 + alerts. Lab ≠ field.
7. Long-session slowdown = memory leak (SPA doesn't reload) → missing cleanup. Confirm with comparison heap snapshots + Detached filter.
8. Caching's hard part = invalidation. Hash solves it for static assets; HTML/API/CDN still need TTLs + tag/surrogate-key purges.