Debounce and Throttle

Debouncing, Throttling and Virtualized Lists

input, scroll, resize and pointermove fire faster than a search request should run. Two wrappers limit the rate:

Debounce and throttle, fed 20 simulated keystrokes 50 ms apart (a module)JavaScript
const debounce = (fn, wait) => {  // run once calls stop for `wait` ms
  let timer;
  return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), wait); };
};
const throttle = (fn, wait) => {  // at most once per `wait` ms, first and last call included
  let last = -Infinity, timer;
  return (...args) => {
    const run = () => { last = performance.now(); fn(...args); };
    clearTimeout(timer);
    const left = last + wait - performance.now();
    if (left <= 0) run(); else timer = setTimeout(run, left);
  };
};
const t0 = performance.now(), log = { debounced: [], throttled: [] };
const rec = (name) => () => log[name].push(Math.round(performance.now() - t0));
const d = debounce(rec('debounced'), 300), t = throttle(rec('throttled'), 300);
for (let i = 0; i < 20; i++) { d(); t(); await new Promise((r) => setTimeout(r, 50)); }
setTimeout(() => console.log(JSON.stringify(log)), 400);
Output
{"debounced":[1394],"throttled":[0,300,613,917,1230]}

Twenty calls became one and five. Lodash 61,278 's debounce adds leading, trailing and maxWait options; a debounced fetch() should also abort its predecessor (Practical Asynchrony).

Virtualized lists

Throttling cannot save 100,000 rows: the nodes themselves are the cost. A virtualized (windowed) list puts one empty spacer total × rowHeight pixels tall in a scroll box, and on each scroll renders only the visible rows plus a few of overscan, absolutely positioned at index × rowHeight. A 240-pixel box holds about 16 rows wherever you scroll. TanStack Virtual 79,069 (https://github.com/TanStack/virtual 7,123 ) (MIT, npm 2,036 install @tanstack/virtual-core, adapters for React 7,897 , Vue 5,482 , Solid 269,718 , Svelte 36,701 and Angular 42,088 ) adds measured row heights and grids. Windowing breaks find-in-page and hides off-screen rows from screen readers, so for a few thousand rows try content-visibility: auto (Visibility) first.