Dcorateur d'acclration
Crez un dcorateur dacclration throttle(f, ms) qui retourne un wrapper.
Lorsquil est appel plusieurs fois, il passe lappel f au maximum une fois par ms millisecondes.
La diffrence avec debounce est que cest un dcorateur compltement diffrent :
debounceexcute la fonction une fois aprs la priode de cooldown. Bon pour traiter le rsultat final.throttlene lexcute pas plus souvent que le temps donn enms. Bon pour les mises jour rgulires qui ne devraient pas tre trs frquentes.
En dautres termes, throttle est comme une secrtaire qui accepte les appels tlphoniques, mais qui drange le patron (appellez le f rel) pas plus dune fois par ms millisecondes.
Examinons lapplication relle pour mieux comprendre cette exigence et voir do elle vient.
Par exemple, nous voulons suivre les mouvements de la souris.
Dans le navigateur, nous pouvons configurer une fonction excuter chaque mouvement de la souris et obtenir lemplacement du pointeur mesure quil se dplace. Pendant une utilisation active de la souris, cette fonction est gnralement utilise trs souvent et peut atteindre 100 fois par seconde (toutes les 10 ms). Nous aimerions mettre jour certaines informations sur la page Web lorsque le pointeur se dplace.
Mais la mise jour de la fonction update() est trop lourde pour tous les micro-mouvements. Il est galement inutile de mettre jour plus dune fois toutes les 100 ms.
Nous allons donc lenvelopper dans le dcorateur : utilisez throttle(update, 100) comme fonction excuter chaque dplacement de souris la place de update() dorigine. Le dcorateur sera appel souvent, mais update() sera appel au maximum une fois toutes les 100 ms.
Visuellement, cela ressemblera ceci:
- Pour le premier mouvement de souris, la variante dcore passe lappel
update. Cela est important, lutilisateur voit notre raction leur mouvement immdiatement. - Puis, alors que la souris continue davancer, il ne se passe plus rien jusqu
100ms. La variante dcore ignore les appels. - la fin de
100msune autreupdatese produit avec les dernires coordonnes. - Enfin, la souris sarrte quelque part. La variante dcore attend que
100msexpire, puis lanceupdateavec les dernires coordonnes. Donc, peut-tre le plus important, les coordonnes finales de la souris sont traites.
Un exemple de code:
function f(a) {
console.log(a);
}
// f1000 passe les appels f au maximum une fois toutes les 1000 ms
let f1000 = throttle(f, 1000);
f1000(1); // montre 1
f1000(2); // (tranglement, 1000ms pas encore coule)
f1000(3); // (tranglement, 1000ms pas encore coule)
// quand 1000ms expirent...
// ...sort 3, la valeur intermdiaire 2 a t ignore
P.S. Les arguments et le contexte this transmis f1000 doivent tre transmis f dorigine.
function throttle(func, ms) {
let isThrottled = false,
savedArgs,
savedThis;
function wrapper() {
if (isThrottled) { // (2)
savedArgs = arguments;
savedThis = this;
return;
}
isThrottled = true;
func.apply(this, arguments); // (1)
setTimeout(function() {
isThrottled = false; // (3)
if (savedArgs) {
wrapper.apply(savedThis, savedArgs);
savedArgs = savedThis = null;
}
}, ms);
}
return wrapper;
}
Un appel throttle(func, ms) retourne wrapper.
- Lors du premier appel, le
wrapperexcute simplementfuncet dfinit ltat de charge (isThrottled = true). - Dans cet tat, tous les appels sont mmoriss dans
savedArgs/savedThis. Veuillez noter que le contexte et les arguments sont dgale importance et doivent tre mmoriss. Nous avons besoin deux simultanment pour reproduire lappel. - Aprs
msmillisecondes,setTimeoutse dclenche. Ltat de charge est supprim (isThrottled = false), et si nous avions ignor les appels, alorswrapperest excut avec les derniers arguments et contextes mmoriss.
La 3me tape nexcute pas func, mais wrapper, car nous devons non seulement excuter func, mais encore une fois entrer dans ltat de charge et configurer le dlai dexpiration pour le rinitialiser.