Contents

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

ThrottleDebounce
Runsregularly while events continueonce, after events stop
Good forscroll position, drag, resize, game inputsearch-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

  • requestAnimationFrame for 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.