Topics in this subject
JavaScript 2 min read Updated 4 Aug 2026

Part 25 — Performance

Debounce & throttle 🎯, Memory leaks — common causes, Loading & rendering

Debounce & throttle 🎯#

ELI12. Debounce = "wait until the user stops, then act once" (search box). Throttle = "act at most once every N ms no matter how often it fires" (scroll/resize).

function debounce(fn, delay) {
  let t;
  return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), delay); };
}
function throttle(fn, limit) {
  let waiting = false;
  return (...args) => {
    if (waiting) return;
    fn(...args); waiting = true;
    setTimeout(() => (waiting = false), limit);
  };
}

Memory leaks — common causes#

  • Forgotten setInterval / listeners on removed elements.
  • Detached DOM nodes still referenced in JS.
  • Ever-growing caches/closures → use WeakMap / cap size (LRU).
  • Global variables holding large data.

Detect with DevTools Memory tab (heap snapshots, allocation timeline).

Loading & rendering#

  • Lazy loading: dynamic import(), <img loading="lazy">, IntersectionObserver.
  • Code splitting: bundlers split routes/features into separate chunks.
  • Memoization: cache pure computations (Part 9).
  • Virtual DOM / virtualization: frameworks diff a lightweight tree; list virtualization renders only visible rows.
  • Avoid layout thrashing: batch DOM reads then writes; use requestAnimationFrame.
  • Profiling: DevTools Performance panel, performance.now(), PerformanceObserver.
const t0 = performance.now();
work();
console.log(performance.now() - t0, "ms");

Interview questions (Part 25):

  1. Debounce vs throttle — implement both, give a use for each.
  2. Name three memory-leak sources in a SPA and how you'd find them.
  3. What is layout thrashing and how do you avoid it?