Blog Hoch
Aug 2026·2 tup leghDe'wI' chenmoHta'

Debouncing 'ej Throttling: JavaScript high-frequency events Qotlh

#javascript#performance#frontend

frontend developer Hoch wa' wall ghor: scroll handler lup Hoch law' Qu', search input keystroke Hoch network request, resize listener layout recalculate (page stutter). Debouncing 'ej throttling cha' technique. pIm Sov vaj Dun choose nom.

Qagh: events handle laH nom

browsers DOM events rate-limit pagh. scroll, resize, mousemove, input lup Hoch law' fire. handler non-trivial (fetch, DOM measurement, re-render) vaj user poQ law' expensive work.

window.addEventListener('resize', () => {
  recalculateLayout(); // runs on every single pixel of resize
});

Debouncing 'ej throttling handler Qu' frequency Dach - guarantees pIm.

Debounce: silence wait

Debouncing execution delay events Qaw' poH. call Hoch timer reset. burst qaSpa' final state neH poQ vaj Dun - search box value user typing Qaw'DI', keystroke Hoch pagh.

function debounce(fn, delayMs) {
  let timeoutId;
  return function debounced(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delayMs);
  };
}

lo': search-as-you-type box network keystroke Hoch hit pagh.

const searchInput = document.querySelector('#search');

const runSearch = debounce((event) => {
  fetchResults(event.target.value);
}, 300);

searchInput.addEventListener('input', runSearch);

"angular" type vaj fetchResults wa'logh 300ms last keystroke qaSDI' - SochDIch pagh.

Throttle: steady rhythm

Throttling execution interval wa'logh Dach, events law' 'ach. continuous streams vaD Dun (periodic updates poQ): scroll position tracker, drag handler, mousemove cursor effect.

function throttle(fn, intervalMs) {
  let lastCall = 0;
  let timeoutId = null;

  return function throttled(...args) {
    const now = Date.now();
    const remaining = intervalMs - (now - lastCall);

    if (remaining <= 0) {
      clearTimeout(timeoutId);
      timeoutId = null;
      lastCall = now;
      fn.apply(this, args);
    } else if (!timeoutId) {
      timeoutId = setTimeout(() => {
        lastCall = Date.now();
        timeoutId = null;
        fn.apply(this, args);
      }, remaining);
    }
  };
}

lo': resize layout recalculate, 200ms wa'logh.

window.addEventListener(
  'resize',
  throttle(() => {
    recalculateLayout();
  }, 200),
);

else if (!timeoutId) branch legh: wa' trailing call schedule. burst last resize event handle (cooldown window Daq silently drop pagh).

choose

  • Debounce end state neH: search input, form validation, auto-save, resize handlers.
  • Throttle activity Dung continuous feedback: infinite scroll triggers, scroll progress bars, drag-and-drop, live cursor tracking.

rule: debounce "nuq Qu'pu'?" jang; throttle "DaH nuq Qu'taH, regularly sampled?" jang.

Qagh law'

  • this Qaw'. cha' implementations fn.apply(this, args) lo'. arrow function wrong this closed over vaj .apply() Qotlh pagh.
  • unmount cleanup pagh. component framework (React, Angular, Vue) handler setTimeout Daq pending (component Qaw'), fire vaj crash pagh stale state ghItlh. cancel: timeoutId reference, cleanup path Daq clear (ngOnDestroy, useEffect cleanup).
  • Debounce delay tIn. 300ms search inputs common; inline form validation vaD 300ms laggy. delay interaction Daq tune (blog post number pagh).
  • Throttle trailing call pagh. naive throttle "poH Dung'a'?" neH legh - burst final event drop. last state qatlh vaj trailing call schedule.

own ghItlh'a'?

implementations minimal (mechanism legh): closures timer state hold. production Daq maintained utility lo': Lodash debounce 'ej throttle edge cases handle (leading/trailing-edge, .cancel()/.flush()). own ghItlh Dun exercise. battle-tested lo' qatlh vaj.

yaj

Debounce burst events wa' call choH (settles qaSDI'). Throttle calls evenly spread (burst Dung). cha' same reason: browser Sovbe' code chay' nom Qu'laH - SoH jatlh poQ.

chu'Web Workers computation tIn vaD yajqanNode.js Daq command-line tool simple ghItlh