Debounce & throttle, by hand
Two utilities I now reach for monthly.
Implement debounce and throttle from first principles. These two utilities are the foundation of performant event handling.
The Problem
Certain events fire a lot — mousemove, scroll, resize, typing in a search box. If you run expensive logic on every single event, you’ll lock up the UI or hammer the server.
debounce and throttle are two strategies to reduce how often a function actually runs.
Debounce
Debounce says: “I’ll wait until the user stops doing something, then run the function once.”
Perfect for: search-as-you-type, form validation, resize handlers.
function debounce(fn, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), delay); };}Every time the function is called, we clear the previous timer and set a new one. The function only actually runs after delay milliseconds of silence.
Throttle
Throttle says: “Run this function at most once every N milliseconds.”
Perfect for: scroll event handlers, mouse tracking, game loops.
function throttle(fn, interval) { let lastRun = 0; return function (...args) { const now = Date.now(); if (now - lastRun >= interval) { fn(...args); lastRun = now; } };}We track the last time the function ran and refuse to run it again until interval milliseconds have passed.
Real Example
// Debounce: search fires once when typing stopsconst handleSearch = debounce((query) => { fetch(`/api/search?q=${query}`);}, 500);
input.addEventListener("input", (e) => handleSearch(e.target.value));
// Throttle: scroll handler runs at most every 100msconst handleScroll = throttle(() => { console.log("Scroll position:", window.scrollY);}, 100);
window.addEventListener("scroll", handleScroll);Why It Matters
Once you understand these patterns, you can apply them anywhere. API calls, UI updates, animations — they all benefit from smart event handling.
I reach for these utilities multiple times a month. Knowing how to implement them from scratch means I understand what they’re actually doing, not just using them as black boxes.