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):
- Debounce vs throttle — implement both, give a use for each.
- Name three memory-leak sources in a SPA and how you'd find them.
- What is layout thrashing and how do you avoid it?