Some browser events are firehoses. Scroll, resize, mousemove and keystroke events can fire dozens or hundreds of times a second, and if you run expensive work on every one — a network request, a layout recalculation, a re-render — the interface stutters and the app feels broken. Two classic techniques, debouncing and throttling, tame these torrents, and choosing correctly between them is most of the battle.
Both limit how often a function runs, but they do it in different ways suited to different jobs, and using the wrong one produces subtly wrong behaviour.
Debouncing: wait for the pause
Debouncing waits until the events stop. It says: "run the function only after nothing has happened for a set quiet period." Every new event resets the timer. This is perfect for a search box that queries as you type — you do not want a request per keystroke; you want one request once the user pauses. Debouncing collapses a burst of activity into a single action at the end.
The mental model: a debounced function is patient. No matter how many times it is triggered, it does nothing until the storm subsides, then acts once. Autocomplete, save-on-idle, and resize-then-recalculate are its natural homes.
Throttling: run at a steady rate
Throttling guarantees a maximum frequency: "run the function at most once every set interval, no matter how many events arrive." Unlike debouncing, it does not wait for a pause — it fires regularly during continuous activity. This suits things that need steady updates while something is happening, like updating a scroll-position indicator or handling a mousemove-driven animation, where waiting for the user to stop would freeze the feedback.
The mental model: a throttled function is disciplined. During a continuous stream it acts on a regular heartbeat, keeping the interface responsive without doing work on every single event.
Choosing between them
The rule of thumb: use debounce when you only care about the final state after activity stops (search input, form validation on pause, saving a draft). Use throttle when you need regular updates during ongoing activity (scroll progress, drag handling, rate-limiting a rapidly clickable button).
Both are only a few lines, and most utility libraries and many frameworks provide them, but writing one yourself once cements the idea. Get the choice right and a janky, request-spamming interface becomes smooth and efficient — a small technique with an outsized effect on how an app feels.