Ich habe diese Begriffe neulich verwechselt und jemand hat mich korrigiert. Also habe ich es auf meine Liste von Blog-Ideen gesetzt und hier sind wir. Beides sind Wege, um die Menge an JavaScript zu begrenzen, die wir aufgrund von DOM-Ereignissen aus Performance-Gründen ausführen. Aber sie sind, Sie haben es erraten, unterschiedlich.
Throttling erzwingt eine maximale Anzahl von Aufrufen einer Funktion über die Zeit. Wie in „Diese Funktion höchstens einmal alle 100 Millisekunden ausführen.“
Angenommen, unter normalen Umständen würden Sie diese Funktion 1.000 Mal über 10 Sekunden aufrufen. Wenn Sie sie auf nur einmal pro 100 Millisekunden drosseln, wird diese Funktion höchstens 100 Mal ausgeführt.
(10s * 1.000) = 10.000 ms
10.000 ms / 100 ms Throttling = 100 maximale Aufrufe
Debouncing erzwingt, dass eine Funktion nicht erneut aufgerufen wird, bis eine bestimmte Zeit vergangen ist, ohne dass sie aufgerufen wurde. Wie in „Diese Funktion nur ausführen, wenn 100 Millisekunden vergangen sind, ohne dass sie aufgerufen wurde.“
Vielleicht wird eine Funktion 1.000 Mal in einem schnellen Burst aufgerufen, verteilt über 3 Sekunden, und dann nicht mehr. Wenn Sie sie mit 100 Millisekunden debounce, wird die Funktion nur einmal, nach 3,1 Sekunden, einmal nach dem Burst feuern. Jedes Mal, wenn die Funktion während des Bursts aufgerufen wird, wird der Debouncing-Timer zurückgesetzt.
Was ist der Sinn?
Ein wichtiger Anwendungsfall für diese Konzepte sind bestimmte DOM-Ereignisse wie Scrollen und Größenänderung. Wenn Sie beispielsweise einen Scroll-Handler an ein Element anhängen und dieses Element um beispielsweise 5000 Pixel nach unten scrollen, werden wahrscheinlich mehr als 100 Ereignisse ausgelöst. Wenn Ihr Ereignis-Handler eine Menge Arbeit leistet (wie z. B. schwere Berechnungen und andere DOM-Manipulationen), kann es zu Leistungsproblemen (Ruckeln) kommen. Wenn Sie den Handler weniger oft ausführen können, ohne die Benutzererfahrung wesentlich zu beeinträchtigen, ist es wahrscheinlich sinnvoll.
Kurze Beispiele
- Warten Sie, bis der Benutzer die Fenstergröße ändert
- Lösen Sie kein Ajax-Ereignis aus, bis der Benutzer mit dem Tippen aufhört
- Messen Sie die Scroll-Position der Seite und reagieren Sie höchstens alle 50 ms
- Sorgen Sie für gute Leistung, während Sie Elemente in einer App ziehen
Wie macht man das?
Funktionen für beides sind in Underscore und Lodash integriert. Selbst wenn Sie diese Bibliotheken nicht vollständig verwenden, könnten Sie die Funktionen daraus extrahieren und für Ihren eigenen Gebrauch verwenden.
Einfaches gedrosseltes Scrollen
$("body").on('scroll', _.throttle(function() {
// Do expensive things
}, 100));
Einfaches debounced Größenänderung
$(window).on('resize', _.debounce(function() {
// Do expensive things
}, 100));
Um dies zu verbessern, würden Sie die Verwendung von requestAnimationFrame einbeziehen, so dass der Browser die Ausführung der Funktionen zu seinem eigenen optimalen Zeitpunkt durchführt. Dies wird in diesem Tutorial von Paul Lewis behandelt.
Demo
Einfache Demo, damit Sie den Unterschied erleben können
Sehen Sie den Pen Der Unterschied zwischen Throttling, Debouncing und Keinem von Chris Coyier (@chriscoyier) auf CodePen.
Update: Mehr Demos!
Ich würde argumentieren, dass zeitbasiertes Debouncing nur einer von mehreren gültigen Ansätzen ist, man kann auch strikt basierend auf unerledigtem Verhalten debouncen.
Betrachten Sie eine Schaltfläche, die eine „In den Warenkorb legen“-Funktion initiiert. Sie möchten sicherstellen, dass auch bei versehentlichem Doppelklick nur ein Artikel in den Warenkorb gelegt wird. Sie können zeitbasiert debouncen (Klick mehr als 500 ms auseinander sind 2 Klicks, nicht 1 Doppelklick) oder Sie können die Funktion mit einer Flag schützen, die weitere Klicks blockiert, bis die Flag als abgeschlossen gelöscht wurde.
Bitte gehen Sie nicht davon aus, dass ich Fehler bei der Interaktion mit einem gängigen UI-Element gemacht habe. Mein Autoradio macht Debouncing, wenn ich versuche, die Station zu schnell zu wechseln, komme ich nicht voran und es macht mich wütend, das Ding aus dem Armaturenbrett zu reißen.
Kein gutes Beispiel, da Sie bereits Zugriff auf das Doppelklick-Ereignis haben. Verhindern Sie einfach eine Aktion bei Doppelklick.
Abgesehen davon, was Chris gesagt hat, ist die Verwendung einer festen Zeitspanne zur Unterscheidung zwischen einem Klick und einem Doppelklick einfach schlecht, da das Betriebssystem dem Benutzer möglicherweise die Konfiguration anbietet, welche Zeitspanne einen Doppelklick darstellt – Ihre 500-ms-Annahme könnte also einfach falsch sein.
Alles gültige Punkte, mein ursprünglicher Gedanke war einfach, dass Debouncing nicht so eindeutig ist, wie es hier definiert wird. Ja, es gibt wahrscheinlich bessere Beispiele, und ja, man sollte absolut vorsichtig sein, wo es eingesetzt wird.
Aber ein Verständnis des Debouncing-Musters, anstatt nur zeitbasiertes Debouncing, ist ein gutes Werkzeug, das man zur Hand haben sollte.
Gibt es einen besonderen Grund, warum das noch nicht standardisiert wurde?
Ich dachte, Underscore wäre ziemlich Standard, ich benutze es auf jeden Fall überall ;)
Lodash ist sozusagen das neue Underscore, das solltest du dir ansehen. Es hat einige zusätzliche nützliche Funktionen, begann als Fork von Underscore.
Im Ernst mit dem „Lodash ist das neue Underscore“
Underscore 53k
Lodash 407k
Lodash ist wahrscheinlich besser für Node.js geeignet
Throttling: Schritt, Schnappschuss, Raster. Beispiel: Permanente Werte bei einem benutzerdefinierten Bereichsschieberegler.
Debouncing: Auf Leerlauf warten. Beispiel: AJAX-Suchergebnisse auslösen, nachdem auf ein Textfeld getippt wurde, Hover-State-Animations-Trick im Dropdown-Menü → das Dropdown-Menü nicht anzeigen, es sei denn, der Benutzer bewegt den Mauszeiger über das übergeordnete Menü.
Wichtiger Hinweis zu Ihrem Throttling-Beispiel: Sie erhalten maximal 100 Aufrufe innerhalb der fraglichen 10 Sekunden.
Die anderen 900 Aufrufe werden gemacht, allerdings über die nächsten 90 Sekunden, zumindest mit der Methode von
underscore.lodashfügt der zurückgegebenen Funktion einecancel-Methode hinzu, mit der Sie alle aktuell verzögerten Aufrufe verwerfen können, wenn Sie möchten.Ich bin mir ziemlich sicher, dass das nicht stimmt. Im Beispiel, das er eingefügt hat, stimmt es sicher nicht.
Sie haben absolut Recht, Jeremy T.
Ich bin mir nicht sicher, was ich mir gedacht habe.