Frontend Development › JavaScript & TypeScript
Throttle
Acting at most once per interval, e.g. for scroll handlers.
Also known as: throttling, rate limit function calls, throttle function
Throttling limits how often a function can run: at most once per interval, however often it’s triggered. It keeps frequent events (scroll, mouse move, resize) from running expensive code hundreds of times a second.
function throttle(fn, ms) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= ms) {
last = now;
fn(...args);
}
};
}
window.addEventListener("scroll", throttle(updateProgressBar, 100));
With a 100 ms throttle, the scroll handler runs at most 10 times a second.
Throttle vs debounce
| Throttle | Debounce | |
|---|---|---|
| Runs | regularly while events continue | once, after events stop |
| Good for | scroll position, drag, resize, game input | search-as-you-type, saving after typing, window resize end |
Throttle says “no more than once per 100 ms”. Debounce says “wait until the user pauses for 300 ms”.
Variations
- Leading edge: run immediately at the first event, then ignore the rest.
- Trailing edge: also run once at the end so the final state isn’t missed.
- Libraries (Lodash
throttle,debounce) handle these options and edge cases. Prefer them to hand-written versions.
Better options sometimes exist
requestAnimationFramefor visual updates, which runs once per frame.- IntersectionObserver instead of scroll handlers to detect visibility.
- ResizeObserver for size changes.
- CSS (
position: sticky, scroll-snap) for many scroll effects. - Passive listeners (
{ passive: true }) for scroll and touch.
Make the handler itself cheap too: read layout values once, and avoid forcing reflows.