Debounce Function
Delays function execution until after specified idle time, ideal for search input, autocomplete, and form validation
Implementation
Copy the complete example or adapt its typed interface to your project. Comments are kept inside the snippet so the intent travels with the code.
/**
* Debounce function implementation
* @param fn Function to debounce
* @param delay Idle time in milliseconds
* @param immediate Execute immediately on first call
* @returns Debounced function
*/
function debounce<T extends (...args: any[]) => void>(fn: T, delay: number, immediate = false): T & { cancel(): void } {
let timeoutId: NodeJS.Timeout | null = null;
const debounced = function(this: ThisParameterType<T>, ...args: Parameters<T>) {
const context = this;
const later = () => {
timeoutId = null;
if (!immediate) fn.apply(context, args);
};
const callNow = immediate && !timeoutId;
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(later, delay);
if (callNow) fn.apply(context, args);
} as T;
debounced.cancel = () => {
if (timeoutId) clearTimeout(timeoutId);
timeoutId = null;
};
return debounced as T & { cancel(): void };
}
// Usage Example
const searchInput = document.getElementById('search-input');
const handleSearch = debounce((e: Event) => {
console.log('Search query:', (e.target as HTMLInputElement).value);
}, 300);
searchInput?.addEventListener('input', handleSearch);When to use it
Perfect for search input autocomplete, form validation, or any scenario where you want to wait for user input to complete
Review the input assumptions and browser or runtime support before adopting a utility unchanged. Small helpers are easiest to maintain when their contract stays narrow.
Reasoning and trade-offs
How it works
Every call clears the previous timer and schedules a new one with the latest arguments. The wrapped function runs only after calls stop for the configured delay, turning a noisy burst into one final execution.
What to watch for
Timers do not guarantee an exact execution instant, and continuous input can postpone work indefinitely. Production versions may need cancellation, immediate leading execution, a maximum wait, preserved return values, and safe async error handling.
Production use
Use debounce for search suggestions, validation, autosave preparation, or layout work triggered by rapid input. Do not debounce actions that must be recorded individually, such as purchases, audit events, or security decisions.
Before you ship
- Confirm the input contract with tests that cover empty, invalid, boundary, and representative real-world values before sharing the helper across a codebase.
- Keep the function focused on one responsibility and name any project-specific policy explicitly instead of hiding it inside a generic-looking utility.
- Measure behavior in the browsers or runtime versions your product supports, especially when timing, storage, DOM state, locale, or network access is involved.
- Document the return type, mutation behavior, failure mode, and performance characteristics beside the call site so future maintainers can evaluate changes safely.
- Compare the example with current official platform documentation when it relies on a browser API, language feature, or runtime behavior that may change over time.
- If the helper crosses a trust boundary, validate again on the server and avoid treating browser-side checks, TypeScript annotations, or formatted output as a security guarantee.
- Add a small regression test whenever a real edge case is discovered; concrete examples preserve the reason behind a guard more reliably than a general comment.