Implémenter debounce et throttle pour optimiser les performances lors de la gestion d'événements fréquents.
Qu'est-ce que le debounce ?
Le debounce retarde l'exécution d'une fonction jusqu'à ce que l'utilisateur ait arrêté de déclencher l'événement pendant un certain délai.
// Sans debounce : la fonction est appelée à chaque frappe clavier
const input = document.querySelector('input');
input.addEventListener('keyup', () => {
someExpensiveFunction(); // Appelé 100x par seconde !
});
// Avec debounce : appelé seulement après 300ms sans frappe
const debounced = debounce(someExpensiveFunction, 300);
input.addEventListener('keyup', debounced);
Qu'est-ce que le throttle ?
Le throttle limite la fréquence d'exécution d'une fonction, l'exécutant au maximum une fois par intervalle de temps spécifié.
// Throttle : exécution limitée à une fois par seconde max
window.addEventListener('scroll', throttle(() => {
console.log('Scroll !');
}, 1000)); // Appelé max 1x/seconde même si le scroll est continu
Implémenter debounce
// Implémentation debounce en JavaScript vanilla
function debounce(func, delay = 300) {
let timerId;
// Retourne une nouvelle fonction qui remet le timer à zéro à chaque appel
return function(...args) {
clearTimeout(timerId);
timerId = setTimeout(() => {
func(...args); // Exécuté seulement si pas de nouvel appel pendant `delay` ms
}, delay);
};
}
// Usage : recherche déclenchée 300ms après la dernière frappe
const handleSearch = debounce(query => {
console.log('Recherche :', query);
}, 300);
const input = document.querySelector('#search');
input.addEventListener('keyup', e => {
handleSearch(e.target.value);
});
Implémenter throttle
// Implémentation throttle en JavaScript vanilla
function throttle(func, limit = 1000) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func(...args); // Exécution immédiate
inThrottle = true;
// Déverrouille après `limit` ms
setTimeout(() => {
inThrottle = false;
}, limit);
}
};
}
// Usage : handler scroll limité à 1 exécution par seconde
const handleScroll = throttle(() => {
console.log('Position :', window.scrollY);
}, 1000);
window.addEventListener('scroll', handleScroll);
Cas d'usage debounce
- Recherche en temps réel (autocomplete, suggestions)
- Sauvegarde automatique de formulaire
- Validation de champ à la saisie
- Redimensionnement de fenêtre (resize)
Cas d'usage throttle
- Scroll infini (infinite scroll)
- Animations liées aux mouvements souris
- Resize handler haute fréquence
- Mouse move tracking et drag & drop
Patterns avancés
Le debounce avec méthode cancel() permet d'annuler l'exécution en attente :
// Debounce avancé avec méthode cancel
function debounce(func, delay) {
let timerId;
const debounced = function(...args) {
clearTimeout(timerId);
timerId = setTimeout(() => func(...args), delay);
};
// Permet d'annuler l'exécution en cours d'attente
debounced.cancel = () => clearTimeout(timerId);
return debounced;
}
const search = debounce(query => console.log(query), 300);
search('test');
search.cancel(); // Annule avant que les 300ms s'écoulent
_.debounce et _.throttle avec des options avancées (leading, trailing, maxWait) pour éviter de réécrire ces utilitaires.
Conclusion
Debounce et throttle sont deux techniques essentielles pour contrôler la fréquence d'exécution des événements JavaScript. Le debounce attend la fin d'une série d'événements, le throttle impose un intervalle minimum entre chaque exécution.
Maîtriser ces deux patterns te permettra d'écrire des interfaces plus performantes et d'éviter les traitements redondants sur les événements haute fréquence comme le scroll, le resize ou la saisie clavier.