Debounce and Throttle
Control how often expensive functions run — search inputs, scroll handlers, and resize listeners — without melting the main thread.
Input and scroll events fire far faster than network or layout can afford. Firing fetch on every keypress DDOSes your own API; running layout reads on every scroll frame janks the UI. Debounce and throttle are timing strategies implemented with closures and setTimeout — interview favorites because they test both event loop understanding and practical product engineering.
Debounce — wait until activity pauses
Debounce delays execution until the caller stops invoking for N milliseconds. Each new call resets the timer. Perfect for search-as-you-type: send the query 300ms after the user stops typing, not on every keystroke. Also used for window resize end detection and auto-save drafts.
API search: jav calls: 1Throttle — at most once per interval
Throttle guarantees the function runs at most once every N ms while events keep coming. Use for scroll position updates, mousemove tracking, and infinite scroll load-more triggers. Leading throttle runs immediately then ignores; trailing throttle runs after the window — pick based on UX.
| Pattern | Behavior | Typical use |
|---|---|---|
| Debounce | Run after pause | Search input, resize end |
| Throttle | Run on interval | Scroll, mousemove, rate limits |
| requestAnimationFrame | Sync to paint | Visual DOM updates |
Debounce and throttle are not browser-only — rate-limit API polling, log batching, and queue flush timers use the same closure patterns. The implementation here is interview-sized; production code may add maxWait, cancel on unmount, and leading-edge options. Understand the mental model first, then reach for lodash.debounce when edge cases multiply.
Measure before optimizing: DevTools Performance panel shows whether scroll handlers or search inputs actually bottleneck your app. Applying throttle to every mousemove without evidence adds complexity. Debounce search at 250–400ms is a sensible default for internal admin tools; public SEO pages may prefer instant local filter with debounced analytics only.
Cancel and flush on unmount
UI components must clear debounce timers on unmount — otherwise setState on unmounted components triggers React warnings. Expose debounced.cancel() and debounced.flush() in library implementations so route changes immediately persist pending search queries when product requires it.
- Debounce: wait for pause — search, resize end, auto-save
- Throttle: cap frequency — scroll, mousemove, sendBeacon batching
- requestAnimationFrame: sync visual reads/writes to paint — not interchangeable with throttle
- 1Debounce: wait for quiet period — search boxes
- 2Throttle: cap frequency — scroll handlers
- 3Both use closures to remember timer state
- 4Clean up timers on component unmount in UI code
- 5Next lesson: structuredClone and immutability