Lassen Sie uns zunächst verstehen, was Gashebel ist
1. Definition
Wenn Sie den Wasserhahn anziehen, bis das Wasser in Form von Wassertropfen ausfließt, werden Sie feststellen, dass ab und zu ein Wassertropfen fließt.
Das heißt, ein Ausführungszyklus wird im Voraus festgelegt, und wenn die Zeit, in der die Aktion aufgerufen wird, größer oder gleich dem Ausführungszyklus ist, wird die Aktion ausgeführt, und dann wird der nächste neue Zyklus eingegeben.
Schnittstellendefinition:
* Wenn die Frequenzsteuerung zurückgibt, wird die Funktion kontinuierlich aufgerufen, die Aktionsausführungsfrequenz ist auf Zeiten/ Verzögerungen beschränkt.
2. Einfache Implementierung
var throttle = function (delay, action) {var last = 0return function () {var curr = +new Date () if (curr - last> delay) {action.apply (this, Argumente) last = curr}}}Lassen Sie mich diese Drosselungsfunktion unten sorgfältig erklären.
Im Browser -DOM -Ereignis werden einige Ereignisse kontinuierlich mit den Vorgängen des Benutzers ausgelöst. Beispiel: Die Größe des Browserfensters ändern, scrollen Sie die Browser -Seite und Mousemove. Das heißt, wenn der Benutzer diese Browseroperationen auslöst, wird diese Methode kontinuierlich ausgelöst, wenn die entsprechende Ereignishandhabungsmethode an das Skript gebunden ist.
Dies ist nicht das, was wir wollen, denn manchmal, wenn die Ereignisbearbeitungsmethode relativ groß ist, werden DOM -Operationen wie komplex und ständig die Ereignisse ausgelöst, was zu einem Rückgang der Benutzererfahrung führt (langsame UI -Reaktion, Browser festgefahren usw.). Normalerweise fügen wir dem entsprechenden Ereignis Logik hinzu, um die Ausführung zu verzögern.
Im Allgemeinen verwenden wir den folgenden Code, um diese Funktion zu implementieren:
var count = 0; Funktion testfn () {console.log (count ++); } // Wenn der Browser die Größe // 1. Löschen Sie den vorherigen Timer // 2. Fügen Sie einen Timer hinzu, um den realen Funktionstestfn um 100 Millisekunden zu verzögern, um das Fenster zu auslösen. Clearimeout (Timer); timer = setTimeout (function () {testfn ();}, 100);};Sorgfältige Schüler werden feststellen, dass der obige Code tatsächlich falsch ist. Dies ist ein Problem, das Anfänger machen werden: Der Rückgabewert der SetTimeout -Funktion sollte in einer relativen globalen Variablen gespeichert werden, da sonst jedes Mal ein neuer Timer generiert wird, wenn die Größe der Größe geändert wird, wodurch der von uns gesendete Effekt nicht erzielt wird.
Also haben wir den Code geändert:
var timer = null; window.onResize = function () {ClearTimeOut (Timer); timer = setTimeout (function () {testfn ();}, 100);};Zu diesem Zeitpunkt ist der Code normal, aber es gibt ein weiteres neues Problem - ein globaler variabler Timer wird generiert. Das wollen wir nicht sehen. Wenn diese Seite andere Funktionen hat, wird sie auch als Timer bezeichnet. Verschiedene Codes verursachen zuvor Konflikte. Um dieses Problem zu lösen, müssen wir eine Sprachfunktion von JavaScript: Verschlusssschluss verwenden. Leser können über verwandte Wissen in MDN lernen. Der geänderte Code lautet wie folgt:
/*** Funktionsdrosselungsmethode* @param Funktion Fn Delay -Aufruffunktion* @param number Verzögerung Wie lang ist die Verzögerung* @return Funktionsmethode zur Verzögerung der Ausführung*/var throttle = Funktion (fn, delay) {var timer = null; return function () {ClearTimeout (Timer); timer = setTimeout (function () {fn ();}, delay); }}; window.onResize = throttle (testfn, 200, 1000);Wir verwenden eine Verschlussfunktion (Drosselklappenrosselung), um den Timer intern zu setzen und die Verzögerungsverarbeitungsfunktion zurückzugeben. Auf diese Weise ist die Timer -Variable außen unsichtbar, aber die Timer -Variable kann auch zugegriffen werden, wenn die interne Verzögerungsfunktion ausgelöst wird.
Natürlich ist diese Schreibmethode für Anfänger nicht einfach zu verstehen. Wir können die Schreibmethode ändern, um zu verstehen:
var throttle = function (fn, delay) {var timer = null; return function () {ClearTimeout (Timer); timer = setTimeout (function () {fn ();}, delay); }}; var f = throttle (testfn, 200); window.onResize = function () {f ();};Hier ist ein Standpunkt: Die Funktion, die nach dem Rufen des Gass zurückgegeben wird, ist die tatsächliche Funktion, die aufgerufen werden muss, wenn die OnResize ausgelöst wird
Jetzt scheint es, dass diese Methode nahezu Perfektion ist, aber bei der tatsächlichen Verwendung nicht der Fall. Zum Beispiel:
Wenn der Benutzer ständig die Größe der Browserfenster ändert
Daher müssen wir eine weitere Funktion hinzufügen: Wenn der Benutzer die Größe der Größe auslöst, sollte er mindestens einmal innerhalb eines bestimmten Zeitraums ausgelöst werden. Da es innerhalb eines bestimmten Zeitraums liegt, kann diese Beurteilungsbedingung die aktuelle Zeit Millisekunden in Anspruch nehmen und jeder Funktionsaufruf die aktuelle Zeit der letzten Anrufzeit subtrahiert. Wenn der Unterschied größer als eine bestimmte Zeitspanne ist, wird sie direkt gesendet, da sie sonst immer noch die Logik für die Zeitleitungsverzögerung folgt.
Was im folgenden Code hingewiesen werden muss, lautet:
Die Funktion der vorherigen Variablen ähnelt der des Timers. Beide sind die Kennungen, die das letzte Mal aufzeichnen und relative globale Variablen sein müssen
Wenn der Logikprozess der Logik "mindestens einmal ausgelöst" folgt, muss der Funktionsaufruf abgeschlossen werden, um die vorherige Zeit zurückzusetzen. Kurz gesagt, es ist tatsächlich der aktuelle im Vergleich zum nächsten Mal.
/*** Funktionsdrosselungsmethode* @Param Funktion Fn Delay Call -Funktion* @param number Verzögerung Wie lang ist die Verzögerung* @param -Nummer, wie lange sie ausgelöst ist var vorher = null; return function () {var now = +new Date (); if (! vorher) vorher = jetzt; if (jetzt - vorher> zumindest) {fn (); // Setzen Sie die letzte Startzeit bis zur Endzeit dieser Zeit zurück } else {ClearTimeout (Timer); timer = setTimeout (function () {fn ();}, delay); }}};üben:
Wir simulieren eine Szene des Drossels, wenn ein Fenster scrolls, dh wenn der Benutzer die Seite nach unten scrolliert, müssen wir einige Methoden drosseln, z. B. die Berechnung der DOM -Position usw., die einen kontinuierlichen Betrieb von DOM -Elementen erfordert.
Der vollständige Code lautet wie folgt:
<! DocType html> <html Lang = "en"> <head> <meta charset = "utf-8"> <title> drosseltell </title> </head> <body> <div style = "Höhe: 5000px"> <div id = "Demo" style = "Position: Fixed; document.getElementById ('Demo'); Funktion testfn () {Demo.innerHtml += 'testfn wurde' ++ count +'Zeit <br>';} var throttle = Funktion (fn, delay, mindestens) {var timer = null; var vorher = null; return function () {var now = +new Date (); if (! vorher) vorher = jetzt; if (mindestens && jetzt - vorher> mindestens) {fn (); // Setzen Sie die letzte Startzeit bis zur Endzeit dieser Zeit zurück Clearimeout (Timer); } else {ClearTimeout (Timer); Timer = setTimeout (function () {fn (); vorher = null;}, delay); }}}}; window.oncroll = throttle (testfn, 200); // window.oncroll = throttle (testfn, 500, 1000); </script> </body> </html>Wir verwenden zwei Fälle, um den Effekt zu testen, nämlich zumindest das zumindest zumindest das Hinzufügen zumindest und nicht zum Hinzufügen:
// Fall 1Window.OnScroll = Throttle (testfn, 200); // Fall 2Window.onscroll = Throttle (testfn, 200, 500);
Fall 1 manifestiert sich als: Testfn wird während des Bild -Scrolling -Vorgangs nicht aufgerufen (kann nicht gestoppt werden) und wird einmal aufgerufen, bis es gestoppt wird. Dies bedeutet, dass der letzte SetTimeout in der Drosselklappe ausgeführt wird. Der Effekt ist wie in der Abbildung dargestellt:
Fall 2 manifestiert sich als: Während des Seitenscrolling -Vorgangs (nicht gestoppt werden) wird TestFN erstmals um 500 ms verzögert (aus mindestens Verzögerungslogik) und dann mindestens alle 500 ms ausführen. Der Effekt ist wie in der Abbildung gezeigt
Wie oben gezeigt, wurden die Effekte, die wir erreichen möchten, eingeführt, und es werden Beispiele bereitgestellt. Ich hoffe, es wird für Freunde in Not hilfreich sein. Die Leser können über einige nachfolgende Hilfsoptimierungen nachdenken, wie z.