Tout d'abord, comprenons ce qu'est l'accélérateur
1. Définition
Si vous resserrez le robinet jusqu'à ce que l'eau s'écoule sous forme de gouttelettes d'eau, vous constaterez que de temps en temps, une goutte d'eau s'écoulera.
C'est-à-dire qu'un cycle d'exécution est défini à l'avance, et lorsque le moment où l'action est appelée est supérieure ou égale au cycle d'exécution, l'action est exécutée, puis le nouveau cycle suivant est entré.
Définition de l'interface:
* Lorsque le contrôle de fréquence renvoie, la fonction est appelée continuellement, la fréquence d'exécution de l'action est limitée à Times / Delay * @param Delay {Number} Temps de retard, unité millisecondes * @param Action {function} demande la fonction associée, et la fonction qui doit être appelée dans l'application réelle * @return {fonction} renvoie la fonction d'appel client * / Throttle (Delay, Action)2. Implémentation simple
var throttle = function (delay, action) {var last = 0return function () {var curr = + new Date () if (curr - dernier> retard) {Action.Apply (this, arguments) last = curr}}}Permettez-moi d'expliquer attentivement cette fonction de limitation ci-dessous.
Dans l'événement du navigateur DOM, certains événements seront déclenchés en continu avec les opérations de l'utilisateur. Par exemple: redimensionnez la fenêtre du navigateur, faites défiler la page du navigateur et MouseMove. C'est-à-dire que lorsque l'utilisateur déclenche ces opérations de navigateur, si la méthode de traitement des événements correspondante est liée au script, cette méthode sera déclenchée en continu.
Ce n'est pas ce que nous voulons, car parfois, si la méthode de traitement des événements est relativement importante, les opérations DOM telles que complexes et déclenchent constamment de tels événements entraîneront des pertes de performances, entraînant une baisse de l'expérience utilisateur (réponse lente, réponse du navigateur, etc.). Ainsi, nous ajouterons généralement une logique à l'événement correspondant pour retarder l'exécution.
D'une manière générale, nous utilisons le code suivant pour implémenter cette fonction:
var count = 0; fonction testfn () {console.log (count ++); } // Lorsque le navigateur redimensionne // 1. Effacez le temporisateur précédent // 2. Ajoutez une minuterie pour retarder la fonction réelle TestFn de 100 millisecondes pour déclencher la fenêtre.onresize = function () {var timer = null; ClearTimeout (temporisateur); timer = setTimeout (function () {testfn ();}, 100);};Les étudiants prudents constateront que le code ci-dessus est en fait faux. C'est un problème que les novices feront: la valeur de retour de la fonction Settimeout doit être enregistrée dans une variable globale relative, sinon un nouveau temporisateur sera généré chaque fois que le redimensionnement est redimensionné, ce qui n'atteindra pas l'effet que nous envoyons.
Nous avons donc modifié le code:
var timer = null; window.onResize = function () {ClearTimeout (timer); timer = setTimeout (function () {testfn ();}, 100);};Pour le moment, le code est normal, mais il y a un autre nouveau problème - un minuteur de variable global est généré. C'est quelque chose que nous ne voulons pas voir. Si cette page a d'autres fonctions, elle est également appelée minuterie. Différents codes entraîneront des conflits auparavant. Pour résoudre ce problème, nous devons utiliser une fonctionnalité linguistique de JavaScript: fermetures de fermetures. Les lecteurs peuvent en apprendre davantage sur les connaissances connexes en MDN. Le code modifié est le suivant:
/ ** * Fonction Méthode d'exécution * @Param Fonction Fn Delay Calling Fonction * @param Numéro Détage Combien de temps dure le retard * @return Fonction Méthode pour retarder l'exécution * / var throttle = fonction (fn, delay) {var timer = null; return function () {cleartimeout (timer); timer = setTimeout (function () {fn ();}, delay); }}; window.onresize = throttle (testfn, 200, 1000);Nous utilisons une fonction de fermeture (limite de gaz) pour mettre la minuterie en interne et retourner la fonction de traitement de retard. De cette façon, la variable temporaire est invisible à l'extérieur, mais la variable de la minuterie est également accessible lorsque la fonction de retard interne est déclenchée.
Bien sûr, cette méthode d'écriture n'est pas facile à comprendre pour les novices. Nous pouvons changer la méthode d'écriture pour comprendre:
var throttle = fonction (fn, delay) {var timer = null; return function () {cleartimeout (timer); timer = setTimeout (function () {fn ();}, delay); }}; var f = throttle (testfn, 200); window.onresize = function () {f ();};Voici un point de vue: la fonction renvoyée par l'accélérateur après avoir été appelée est la fonction réelle qui doit être appelée lorsque l'on-révision est déclenchée
Maintenant, il semble que cette méthode soit proche de la perfection, mais ce n'est pas le cas dans une utilisation réelle. Par exemple:
Si l'utilisateur redimensionne constamment la taille de la fenêtre du navigateur, la fonction de traitement de retard ne sera pas exécutée une fois
Nous devons donc ajouter une autre fonction: lorsque l'utilisateur déclenche le redimensionnement, il doit être déclenché au moins une fois dans un certain délai. Puisqu'il se trouve dans un certain délai, cette condition de jugement peut prendre le temps actuel des millisecondes, et chaque appel de fonction soustrait l'heure actuelle du dernier temps d'appel, puis juge que si la différence est supérieure à une certaine période de temps, elle sera directement envoyée, sinon elle suivra toujours la logique de retard de délai.
Ce qui doit être souligné dans le code suivant est:
La fonction de la variable précédente est similaire à celle de la minuterie. Les deux sont les identificateurs qui enregistrent la dernière fois et doivent être des variables mondiales relatives
Si le processus logique suit la logique "déclenchée au moins une fois", l'appel de fonction doit être terminé pour réinitialiser l'heure actuelle. En bref, c'est en fait celui actuel par rapport à la prochaine fois.
/ ** * Fonction Méthode d'exécution * @param Fonction Fn Delay Call Fonction * @param Numéro Détage Combien de temps est le retard * @param numéro au moins combien de temps est-il déclenché * @return Fonction Méthode pour retarder l'exécution * / var throttle = fonction (fn, delay, au moins) {var Timer = null; var précédent = null; return function () {var now = + new Date (); si (! Précédent) Précédent = maintenant; if (maintenant - précédent> au moins) {fn (); // Réinitialise l'heure de début à la fin de cette époque précédente = maintenant; } else {cleartimeout (timer); timer = setTimeout (function () {fn ();}, delay); }}};pratique:
Nous simulons une scène de limitation lorsqu'une fenêtre défile, c'est-à-dire lorsque l'utilisateur fait défiler la page vers le bas, nous devons étrangler certaines méthodes, telles que: calcul de la position DOM, etc., qui nécessite un fonctionnement continu des éléments DOM.
Le code complet est le suivant:
<! Doctype html> <html lang = "en"> <éread> <meta charset = "utf-8"> <itle> throttle </ title> </ head> <body> <div style = "height: 5000px"> <div id = "Demo" style = "position: fixe;"> </ div> </v> </cript> var count = 0, de Demo = Demo = document.getElementById («démo»); fonction testfn () {demo.innerhtml + = 'testfn a été appelé' + ++ count + 'Time <br>';} var throttle = fonction (fn, retard, au moins) {var timer = null; var précédent = null; return function () {var now = + new Date (); si (! Précédent) Précédent = maintenant; if (au moins && maintenant - précédent> au moins) {fn (); // Réinitialise l'heure de début à la fin de cette époque précédente = maintenant; ClearTimeout (temporisateur); } else {cleartimeout (timer); timer = setTimeout (function () {fn (); PREMER = NULL;}, delay); }}}}; window.onscroll = throttle (testfn, 200); // window.onscroll = throttle (testfn, 500, 1000); </cript> </ body> </html>Nous utilisons deux cas pour tester l'effet, à savoir l'ajout de déclenchement au moins au moins au moins et à ne pas ajouter:
// cas 1Window.onscroll = Throttle (testfn, 200); // cas 2Window.onscroll = Throttle (TestFn, 200, 500);
Le cas 1 se manifeste comme: TestFN ne sera pas appelé pendant le processus de défilement de la page (ne peut pas être arrêté) et sera appelé une fois jusqu'à ce qu'il s'arrête, ce qui signifie que le dernier temps de set dans l'accélérateur est exécuté, l'effet est comme indiqué sur la figure:
Le cas 2 se manifeste comme suit: Pendant le processus de défilement de la page (ne peut pas être arrêté), TestFN sera retardé de 500 ms pour la première fois (à partir de la logique au moins de retard), puis exécuter au moins toutes les 500 ms. L'effet est comme indiqué sur la figure
Comme indiqué ci-dessus, les effets que nous souhaitons réaliser ont été introduits et des exemples sont fournis. J'espère que ce sera utile aux amis dans le besoin. Les lecteurs peuvent penser à quelques optimisations auxiliaires ultérieures par elles-mêmes, telles que: fonctionnez ce pointage, l'enregistrement de la valeur de retour, etc. Quoi qu'il en soit, il se sent bien de comprendre attentivement ce processus!