1. What is the difference between debouncing and throttling?
Debouncing waits for a pause in events before executing. The function runs only after the user stops triggering events. Throttling ensures the function executes at most once per specified interval, regardless of how many times the event fires. Debouncing is like waiting for an elevator to fill before closing doors. Throttling is like an elevator departing every 5 minutes. Use debouncing for search, form validation, window resize. Use throttling for scroll events, mouse movement, infinite scroll. Throttling guarantees execution frequency. Debouncing may never execute if events keep firing. Understanding both techniques is crucial for performance optimization.
// THROTTLE IMPLEMENTATION
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => {
inThrottle = false;
}, limit);
}
};
}
// COMPARISON
// Debounce: waits for pause
// Events: |x|x|x|x|______|x|x|______
// Executes: ^ ^
// (only after pauses)
// Throttle: executes at intervals
// Events: |x|x|x|x|x|x|x|x|x|x|x|
// Executes: ^ ^ ^ ^ ^
// (every N milliseconds)
// PRACTICAL EXAMPLE - Scroll event
function handleScroll() {
console.log('Scroll position:', window.scrollY);
// Update UI based on scroll
}
// Without optimization: hundreds of calls per scroll
window.addEventListener('scroll', handleScroll);
// With throttle: max one call per 100ms
window.addEventListener('scroll', throttle(handleScroll, 100));
// With debounce: only after scrolling stops
window.addEventListener('scroll', debounce(handleScroll, 100));
// INFINITE SCROLL
const loadMore = throttle(() => {
const scrollPosition = window.scrollY + window.innerHeight;
const threshold = document.body.scrollHeight - 200;
if (scrollPosition >= threshold) {
console.log('Loading more items...');
// Load more data
}
}, 200);
window.addEventListener('scroll', loadMore);
// MOUSE MOVEMENT TRACKING
const trackMouse = throttle((e) => {
console.log('Mouse at:', e.clientX, e.clientY);
// Update cursor effect
}, 50);
document.addEventListener('mousemove', trackMouse);
// BUTTON CLICK RATE LIMITING
const handleClick = throttle(() => {
console.log('API call made');
// Make API call
}, 2000);
button.addEventListener('click', handleClick);
// Can only call once every 2 seconds
// ADVANCED THROTTLE (leading and trailing)
function throttleAdvanced(func, limit, options = {}) {
let timeout;
let previous = 0;
const { leading = true, trailing = true } = options;
return function(...args) {
const now = Date.now();
if (!previous && !leading) {
previous = now;
}
const remaining = limit - (now - previous);
if (remaining <= 0) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(this, args);
} else if (!timeout && trailing) {
timeout = setTimeout(() => {
previous = leading ? Date.now() : 0;
timeout = null;
func.apply(this, args);
}, remaining);
}
};
}
// WHEN TO USE WHAT
// Use DEBOUNCE for:
// - Search input (wait for user to finish typing)
// - Form validation (validate after user stops)
// - Window resize (recalculate layout after resize stops)
// - Autosave (save after user stops editing)
// Use THROTTLE for:
// - Scroll events (update UI while scrolling)
// - Mouse movement (track cursor position)
// - Animation updates (limit frame rate)
// - API rate limiting (max calls per time period)
// - Infinite scroll (check position while scrolling)
// COMBINED EXAMPLE
const searchInput = document.getElementById('search');
// Debounce for search API call
const debouncedSearch = debounce((query) => {
fetch(`/api/search?q=${query}`);
}, 500);
// Throttle for character count update
const throttledCount = throttle((text) => {
document.getElementById('count').textContent = text.length;
}, 100);
searchInput.addEventListener('input', (e) => {
const value = e.target.value;
debouncedSearch(value); // API call debounced
throttledCount(value); // Count update throttled
});
// PERFORMANCE IMPACT
// Without optimization:
// 1000 events = 1000 function calls
// With throttle (100ms):
// 1000 events in 1 second = 10 function calls
// With debounce (100ms):
// 1000 events in 1 second = 1 function call (after pause)