Ich interessiere mich für die Funktion "Entprellen" in Javascript, die hier geschrieben steht: http://davidwalsh.name/javascript-debounce-function
Leider ist der Code nicht klar genug erklärt, damit ich ihn verstehen kann. Kann mir jemand helfen, herauszufinden, wie es funktioniert (ich habe meine Kommentare unten hinterlassen). Kurz gesagt, ich verstehe einfach nicht wirklich, wie das funktioniert
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
BEARBEITEN: Das kopierte Code-Snippet befand sich zuvor callNow
an der falschen Stelle.
javascript
debouncing
Startec
quelle
quelle
clearTimeout
mit etwas anrufen , das keine gültige Timer-ID ist, wird nichts unternommen.WindowTimers
Objekts identifiziert, für das die Methode aufgerufen wurde, führt die Methode nichts aus."Antworten:
Der Code in der Frage wurde geringfügig gegenüber dem Code im Link geändert. In dem Link wird
(immediate && !timeout)
geprüft, BEVOR Sie ein neues Zeitlimit erstellen. Wenn Sie es nachher haben, wird der Sofortmodus niemals ausgelöst. Ich habe meine Antwort aktualisiert, um die Arbeitsversion über den Link zu kommentieren.quelle
immediate && timeout
Scheck. Wird es nicht immer eine gebentimeout
(weiltimeout
früher aufgerufen wird). Was nütztclearTimeout(timeout)
es auch, wenn es früher deklariert (undefiniert) und gelöscht wirdimmediate && !timeout
Prüfung erfolgt, wenn das Entprellen mit demimmediate
Flag konfiguriert ist . Dadurch wird die Funktion sofort ausgeführt, es wird jedoch einewait
Zeitüberschreitung festgelegt, bevor sie erneut ausgeführt werden kann. Der!timeout
Teil sagt also im Grunde "Entschuldigung, Bub, dies wurde bereits innerhalb des definierten Fensters ausgeführt". Denken Sie daran, dass die Funktion setTimeout es löscht und den nächsten Aufruf ausführen kann.setTimeout
Funktion auf null gesetzt werden? Außerdem habe ich diesen Code für mich ausprobiert. Durch dietrue
sofortige Übergabe wird lediglich verhindert, dass die Funktion überhaupt aufgerufen wird (anstatt nach einer Verzögerung aufgerufen zu werden). Passiert das für dich?Das Wichtigste dabei ist, dass
debounce
eine Funktion erzeugt wird, die über dertimeout
Variablen "geschlossen" ist. Dietimeout
Variable bleibt bei jedem Aufruf der erzeugten Funktion auch nach ihrerdebounce
Rückkehr zugänglich und kann über verschiedene Aufrufe wechseln.Die allgemeine Idee für
debounce
ist die folgende:Der erste Punkt ist gerecht
var timeout;
, es ist in der Tat gerechtundefined
. GlücklicherweiseclearTimeout
ist die Eingabe ziemlich lasch: Wenn Sie eineundefined
Timer- ID übergeben, wird nichts unternommen, es wird kein Fehler oder ähnliches ausgegeben.Der zweite Punkt wird von der erzeugten Funktion erledigt. Es speichert zunächst einige Informationen über den Aufruf (den
this
Kontext und denarguments
) in Variablen, damit diese später für den entprellten Anruf verwendet werden können. Es löscht dann das Zeitlimit (falls es einen Satz gab) und erstellt dann einen neuen, um ihn durch zu ersetzensetTimeout
. Beachten Sie, dass dies den Wert von überschreibttimeout
und dieser Wert bei mehreren Funktionsaufrufen bestehen bleibt! Dadurch kann das Entprellen tatsächlich funktionieren: Wenn die Funktion mehrmals aufgerufen wird,timeout
wird sie mehrmals mit einem neuen Timer überschrieben. Wenn dies nicht der Fall wäre, würden mehrere Anrufe dazu führen, dass mehrere Timer gestartet werden, die alle aktiv bleiben - die Anrufe würden einfach verzögert, aber nicht entprellt.Der dritte Punkt wird im Timeout-Rückruf erledigt. Es setzt die
timeout
Variable zurück und führt den eigentlichen Funktionsaufruf unter Verwendung der gespeicherten Aufrufinformationen aus .Das
immediate
Flag soll steuern, ob die Funktion vor oder nach dem Timer aufgerufen werden soll . Wenn dies der Fall istfalse
, wird die ursprüngliche Funktion erst aufgerufen, nachdem der Timer gedrückt wurde. Wenn diestrue
der Fall ist , wird die ursprüngliche Funktion zuerst aufgerufen und erst dann aufgerufen, wenn der Timer erreicht ist.Ich glaube jedoch, dass die
if (immediate && !timeout)
Prüfung falsch ist:timeout
Wurde gerade auf die von zurückgegebene Timer-ID gesetztsetTimeout
,!timeout
ist also immerfalse
an diesem Punkt und daher kann die Funktion niemals aufgerufen werden. Die aktuelle Version von underscore.js scheint eine etwas andere Prüfung zu haben, bei der sieimmediate && !timeout
vor dem Aufruf ausgewertet wirdsetTimeout
. (Der Algorithmus ist auch etwas anders, z. B. wird er nicht verwendetclearTimeout
.) Deshalb sollten Sie immer versuchen, die neueste Version Ihrer Bibliotheken zu verwenden. :-)quelle
!timeout
am Ende nachsehen? Warum existiert es nicht immer (weil es aufsetTimeout(function() etc.)
debounce
, ja, aber es wird von Aufrufen der zurückgegebenen Funktion (die die Funktion ist, die Sie verwenden werden) geteilt. In bleibtg = debounce(f, 100)
der Wert von beispielsweise beitimeout
mehreren Aufrufen von besteheng
. Die!timeout
Überprüfung am Ende ist meines Erachtens ein Fehler und nicht im aktuellen Code von underscore.js enthalten.null
. In meinen Tests mit dem obigen Code wird die Funktion, wenn Sie sofort auf true setzen, überhaupt nicht aufgerufen, wie Sie erwähnt haben. Irgendeine Lösung ohne Unterstrich?Entprellte Funktionen werden beim Aufrufen nicht ausgeführt. Sie warten vor der Ausführung über eine konfigurierbare Dauer auf eine Aufrufpause. Jeder neue Aufruf startet den Timer neu.
Gedrosselte Funktionen werden ausgeführt und warten eine konfigurierbare Dauer, bevor sie erneut ausgelöst werden können.
Debounce eignet sich hervorragend für Tastendruckereignisse. Wenn der Benutzer mit der Eingabe beginnt und dann pausiert, senden Sie alle Tastendrücke als einzelnes Ereignis, wodurch die Bearbeitungsaufrufe reduziert werden.
Throttle eignet sich hervorragend für Echtzeit-Endpunkte, die der Benutzer nur einmal pro festgelegten Zeitraum aufrufen darf.
Schauen Sie sich auch Underscore.js für ihre Implementierungen an.
quelle
Ich habe einen Beitrag mit dem Titel Demistifying Debounce in JavaScript geschrieben, in dem ich genau erkläre, wie eine Debounce-Funktion funktioniert, und eine Demo einbinde .
Auch ich habe nicht ganz verstanden, wie eine Entprellungsfunktion funktioniert, als ich zum ersten Mal auf eine gestoßen bin. Obwohl sie relativ klein sind, verwenden sie tatsächlich einige ziemlich fortgeschrittene JavaScript-Konzepte! Ein guter Überblick über Umfang, Verschlüsse und die
setTimeout
Methode hilft dabei.Nachstehend wird die grundlegende Entprellungsfunktion erläutert und in meinem oben genannten Beitrag vorgeführt.
Das fertige Produkt
Die Erklärung
quelle
Was Sie tun möchten, ist Folgendes: Wenn Sie versuchen, eine Funktion direkt nach der anderen aufzurufen, sollte die erste abgebrochen werden und die neue sollte auf eine bestimmte Zeitüberschreitung warten und dann ausgeführt werden. Sie benötigen also eine Möglichkeit, das Timeout der ersten Funktion abzubrechen? Aber wie? Sie können die Funktion aufrufen, die zurückgegebene Timeout-ID übergeben und diese ID dann an neue Funktionen übergeben. Aber die obige Lösung ist viel eleganter.
Dadurch wird die
timeout
Variable effektiv im Bereich der zurückgegebenen Funktion verfügbar gemacht. Wenn also ein 'resize'-Ereignis ausgelöst wird, wird es nichtdebounce()
erneut aufgerufen , daher wird dertimeout
Inhalt nicht geändert (!) Und ist weiterhin für den "nächsten Funktionsaufruf" verfügbar.Das Wichtigste dabei ist, dass wir die interne Funktion jedes Mal aufrufen, wenn wir ein Größenänderungsereignis haben. Vielleicht ist es klarer, wenn wir uns vorstellen, dass sich alle Größenänderungsereignisse in einem Array befinden:
Sie sehen, dass
timeout
für die nächste Iteration verfügbar ist? Und es gibt keinen Grund, meiner Meinung nach Umbenennungsthis
zucontent
undarguments
zuargs
.quelle
this
undarguments
Änderungen innerhalb der Rückruffunktion setTimeout (). Sie müssen eine Kopie an anderer Stelle aufbewahren, sonst gehen diese Informationen verloren.Dies ist eine Variante, die die entprellte Funktion beim ersten Aufruf immer mit aussagekräftigeren Variablen auslöst:
quelle
Einfache Debounce-Methode in Javascript
Laufzeitbeispiel JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/
quelle
Einfache Entprellfunktion: -
HTML: -
Javascript: -
quelle