How to Prevent a Function from Being Called Multiple Times in JavaScript
When building web applications, you'll often encounter situations where you need to prevent a function from being called multiple times in quick succession. This could be for:
- Button click handlers
- API calls
- Scroll/resize events
- Form submissions
Here are 4 reliable solutions:
1. Debouncing
function debounce(func, delay) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, arguments), delay);
};
}
// Usage:
const processInput = debounce(() => {
console.log('Processing input...');
}, 500);
Best for: Search inputs, resize events
2. Throttling
function throttle(func, limit) {
let inThrottle;
return function() {
if (!inThrottle) {
func.apply(this, arguments);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage:
window.addEventListener('scroll', throttle(() => {
console.log('Scroll handler called');
}, 1000));
Best for: Scroll events, game controls
3. Execution Flags
let isProcessing = false;
function submitForm() {
if (isProcessing) return;
isProcessing = true;
// Perform action
fetch('/api').finally(() => isProcessing = false);
}
Best for: Form submissions, payment processing
4. Promise-Based Lock
let promiseLock = null;
async function fetchData() {
if (promiseLock) return promiseLock;
promiseLock = fetch('/api/data')
.then(response => response.json())
.finally(() => promiseLock = null);
return promiseLock;
}
Best for: API calls, resource loading
Performance Comparison
Method |
Use Case |
Memory |
CPU |
Debouncing |
Input handlers |
Low |
Low |
Throttling |
Scroll/resize events |
Low |
Med |
Flags |
Form submissions |
None |
Low |
Promise Lock |
API requests |
Med |
Low |
Pro Tip: For React applications, consider using useCallback
with dependencies to prevent unnecessary re-renders.