Search-as-you-type, scroll handlers, and resize listeners can fire dozens of times per second — debounce and throttle are the two standard techniques for taming that firehose of events.
// Debounce: waits until events STOP firing, then runs once
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
// Throttle: runs at most once per interval, no matter how often called
function throttle(fn, interval) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= interval) {
lastCall = now;
fn(...args);
}
};
}
searchInput.addEventListener('input', debounce(handleSearch, 300));
window.addEventListener('scroll', throttle(handleScroll, 100));
Use debounce for search-as-you-type (you want the API call only after the user stops typing) and throttle for scroll/resize handlers (you want regular updates while the event is actively firing, just not on every single pixel of movement).