Write a debounce(fn, delay) utility that delays calling fn until 'delay' ms have passed since the last invocation.
Keep a timer in a closure. Each call clears the pending timer and schedules a new one, so fn runs only after a quiet gap. Preserve 'this' and arguments so it works as a method or event handler.
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// const onSearch = debounce(query => api.search(query), 300);Debouncing a search-as-you-type handler turns dozens of keystroke API calls into a single call after the user pauses — critical for both UX and rate limits.
Someone writes const onScroll = debounce(handler, 200) but passes handler.bind(obj) and loses live 'this'. Why does using an arrow inside debounce matter?