Was ist die “Entprellen”-Funktion in JavaScript?

Lesezeit: 20 Minuten

Benutzeravatar von Startec
Startec

Ich interessiere mich für die “Entprellen”-Funktion in JavaScript, at JavaScript-Entprellfunktion.

Leider ist der Code für mich nicht klar genug erklärt, um ihn zu verstehen. Wie funktioniert es (ich habe meine Kommentare unten hinterlassen)? Kurz gesagt, ich verstehe einfach nicht, 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);
    };
};

Das zuvor kopierte Code-Snippet hatte callNow an der falschen Stelle.

  • Wenn Sie anrufen clearTimeout mit etwas, das keine gültige Timer-ID ist, tut es nichts.

    – Ry-

    2. Juni 2014 um 23:22 Uhr

  • @false, ist das gültiges Standardverhalten?

    – Schrittmacher

    2. Juni 2014 um 23:37 Uhr

  • @ Pacerier Ja, das ist es in der spez: “Wenn Handle keinen Eintrag in der Liste der aktiven Timer der WindowTimers Objekt, auf dem die Methode aufgerufen wurde, tut die Methode nichts.”

    – Mattias Bülens

    2. Juni 2014 um 23:43 Uhr

  • Dieser Blog ist sehr hilfreich Endlosschleife

    – snegi

    30. September 2020 um 1:28 Uhr

Malks Benutzeravatar
Malk

Der Code in der Frage wurde gegenüber dem Code im Link geringfügig geändert. In dem Link gibt es ein Häkchen für (immediate && !timeout) Vor Erstellen einer neuen Auszeit. Wenn Sie es danach haben, wird der Sofortmodus nie ausgelöst. Ich habe meine Antwort aktualisiert, um die Arbeitsversion über den Link zu kommentieren.

function debounce(func, wait, immediate) {
  // 'private' variable for instance
  // The returned function will be able to reference this due to closure.
  // Each call to the returned function will share this common timer.
  var timeout;

  // Calling debounce returns a new anonymous function
  return function() {
    // reference the context and args for the setTimeout function
    var context = this,
      args = arguments;

    // Should the function be called now? If immediate is true
    //   and not already in a timeout then the answer is: Yes
    var callNow = immediate && !timeout;

    // This is the basic debounce behaviour where you can call this
    //   function several times, but it will only execute once
    //   (before or after imposing a delay).
    //   Each time the returned function is called, the timer starts over.
    clearTimeout(timeout);

    // Set the new timeout
    timeout = setTimeout(function() {

      // Inside the timeout function, clear the timeout variable
      // which will let the next execution run when in 'immediate' mode
      timeout = null;

      // Check if the function already ran with the immediate flag
      if (!immediate) {
        // Call the original function with apply
        // apply lets you define the 'this' object as well as the arguments
        //    (both captured before setTimeout)
        func.apply(context, args);
      }
    }, wait);

    // Immediate mode and no wait timer? Execute the function...
    if (callNow) func.apply(context, args);
  }
}

/////////////////////////////////
// DEMO:

function onMouseMove(e){
  console.clear();
  console.log(e.x, e.y);
}

// Define the debounced function
var debouncedMouseMove = debounce(onMouseMove, 50);

// Call the debounced function on every mouse move
window.addEventListener('mousemove', debouncedMouseMove);

  • für die immediate && timeout überprüfen. Wird es nicht immer eine geben timeout (Weil timeout wird früher aufgerufen). Auch was Gutes tut clearTimeout(timeout) tun, wenn es früher deklariert (wodurch es undefiniert wird) und gelöscht wird

    – Startec

    3. Juni 2014 um 4:23 Uhr

  • Das immediate && !timeout Prüfung ist, wenn Entprellung mit konfiguriert ist immediate Flagge. Dadurch wird die Funktion sofort ausgeführt, aber a auferlegt wait Timeout bevor if erneut ausgeführt werden kann. Also die !timeout Teil sagt im Grunde ‘Entschuldigung, Bub, das wurde bereits innerhalb des definierten Fensters ausgeführt’ … denken Sie daran, dass die setTimeout-Funktion es löscht und den nächsten Aufruf ausführen lässt.

    – Malk

    3. Juni 2014 um 17:18 Uhr


  • Warum muss timeout innerhalb von auf null gesetzt werden? setTimeout Funktion? Außerdem habe ich diesen Code ausprobiert, für mich, vorbei true denn sofort verhindert nur, dass die Funktion überhaupt aufgerufen wird (und nicht erst nach einer Verzögerung). Ist dies bei Ihnen der Fall?

    – Startec

    3. Juni 2014 um 20:30 Uhr

  • Ich habe eine ähnliche Frage zu sofort? warum muss es den unmittelbaren param haben. Das Setzen von wait auf 0 sollte den gleichen Effekt haben, oder? Und wie @Startec erwähnt hat, ist dieses Verhalten ziemlich seltsam.

    – nullliu

    6. Juli 2015 um 19:21 Uhr

  • Wenn Sie die Funktion nur aufrufen, können Sie keinen Wartezeitgeber festlegen, bevor diese Funktion erneut aufgerufen werden kann. Stellen Sie sich ein Spiel vor, bei dem der Benutzer die Feuertaste drückt. Sie möchten, dass dieses Feuer sofort ausgelöst wird, aber für weitere X Millisekunden nicht erneut ausgelöst wird, egal wie schnell der Benutzer den Knopf drückt.

    – Malk

    10. Juli 2015 um 19:54 Uhr

Benutzeravatar von Mattias Buelens
Mattias Bülens

Das Wichtige, was hier zu beachten ist, ist das debounce produziert ein Funktion das ist “geschlossen über”. timeout Variable. Das timeout Variable bleibt bei jedem Aufruf der produzierten Funktion auch danach zugänglich debounce selbst ist zurückgekehrt, und kann verschiedene Rufe umstellen.

Die allgemeine Idee für debounce ist das Folgende:

  1. Beginnen Sie ohne Zeitüberschreitung.
  2. Wenn die produzierte Funktion aufgerufen wird, löschen und setzen Sie das Zeitlimit zurück.
  3. Wenn das Timeout erreicht ist, rufen Sie die ursprüngliche Funktion auf.

Der erste Punkt ist gerecht var timeout;es ist in der Tat gerecht undefined. Glücklicherweise, clearTimeout ist ziemlich lax in Bezug auf seine Eingabe: Übergeben von an undefined Timer-Bezeichner bewirkt, dass es einfach nichts tut, es wirft keinen Fehler oder so etwas aus.

Der zweite Punkt wird von der produzierten Funktion erledigt. Es speichert zunächst einige Informationen über den Anruf (die this Kontext und die arguments) in Variablen, damit es diese später für den entprellten Anruf verwenden kann. Es löscht dann das Timeout (falls es ein Set gab) und erstellt dann ein neues, um es zu ersetzen setTimeout. Beachten Sie, dass dies den Wert von überschreibt timeout und dieser Wert bleibt über mehrere Funktionsaufrufe bestehen! Dadurch funktioniert die Entprellung tatsächlich: Wird die Funktion mehrfach aufgerufen, timeout wird mehrfach mit einem neuen Timer überschrieben. Wäre dies nicht der Fall, würden mehrere Aufrufe dazu führen, dass mehrere Timer gestartet würden alle aktiv bleiben – die Anrufe würden lediglich verzögert, aber nicht entprellt.

Der dritte Punkt erfolgt im Timeout-Callback. Es setzt die timeout Variable und führt den eigentlichen Funktionsaufruf unter Verwendung der gespeicherten Aufrufinformationen aus.

Das immediate Flag soll steuern, ob die Funktion aufgerufen werden soll Vor oder nach die Zeitschaltuhr. Wenn ja falsewird die ursprüngliche Funktion erst aufgerufen nach der Timer wird getroffen. Wenn ja truedie ursprüngliche Funktion ist Erste angerufen und wird nicht mehr angerufen, bis der Timer erreicht ist.

Allerdings glaube ich, dass die if (immediate && !timeout) Prüfung ist falsch: timeout wurde gerade auf die Timerkennung gesetzt, die von zurückgegeben wurde setTimeout Also !timeout ist immer false an diesem Punkt und somit kann die Funktion niemals aufgerufen werden. Die aktuelle Version von underscore.js scheint eine etwas andere Prüfung zu haben, wo es auswertet immediate && !timeout Vor Berufung setTimeout. (Der Algorithmus ist auch etwas anders, z. B. verwendet er nicht clearTimeout.) Deshalb sollten Sie immer versuchen, die neueste Version Ihrer Bibliotheken zu verwenden. 🙂

  • “Beachten Sie, dass dies den Wert von timeout überschreibt und dieser Wert über mehrere Funktionsaufrufe hinweg bestehen bleibt” Ist timeout nicht lokal für jeden Debounce-Aufruf? Es wird mit var deklariert. Wie wird es jedes Mal überschrieben? Warum auch prüfen !timeout Am Ende? Warum existiert es nicht immer (weil es auf setTimeout(function() etc.)

    – Startec

    3. Juni 2014 um 3:36 Uhr

  • @Startec Es ist bei jedem Anruf von lokal debounceja, aber es wird zwischen den Anrufen geteilt zurückgegebene Funktion (Das ist die Funktion, die Sie verwenden werden). Zum Beispiel im g = debounce(f, 100)der Wert von timeout bleibt über mehrere Aufrufe bestehen g. Das !timeout Check am Ende ist meiner Meinung nach ein Fehler, und es ist nicht im aktuellen underscore.js-Code enthalten.

    – Mattias Bülens

    3. Juni 2014 um 10:48 Uhr


  • Warum muss die Zeitüberschreitung früh in der Rückgabefunktion gelöscht werden (direkt nachdem sie deklariert wurde)? Außerdem wird es dann innerhalb der setTimeout-Funktion auf null gesetzt. Ist das nicht überflüssig? (Zuerst wird es gelöscht, dann wird es auf gesetzt null. In meinen Tests mit dem obigen Code führt das Setzen von „immediate“ auf „true“ dazu, dass die Funktion, wie Sie erwähnt haben, überhaupt nicht aufgerufen wird. Irgendeine Lösung ohne Unterstrich?

    – Startec

    4. Juni 2014 um 10:26 Uhr

Benutzeravatar von jurassix
Jura

Entprellte Funktionen werden nicht ausgeführt, wenn sie aufgerufen werden. Sie warten auf eine Pause von Aufrufen über eine konfigurierbare Dauer, bevor sie ausgeführt werden; jeder neue Aufruf startet den Timer neu.

Gedrosselte Funktionen werden ausgeführt und warten dann eine konfigurierbare Dauer, bevor sie erneut ausgelöst werden können.

Debounce eignet sich hervorragend für Keypress-Events; Wenn der Benutzer mit der Eingabe beginnt und dann pausiert, übermitteln Sie alle Tastendrücke als ein einziges Ereignis, wodurch die Verarbeitung von Aufrufen reduziert wird.

Throttle eignet sich hervorragend für Echtzeit-Endpunkte, die Sie dem Benutzer nur einmal pro festgelegtem Zeitraum erlauben möchten.

Kasse Unterstrich.js auch für ihre Umsetzung.

Ich habe einen Beitrag mit dem Titel geschrieben Demistifying Debounce in JavaScript wo ich genau erkläre wie eine Entprellfunktion funktioniert und eine Demo enthalten.

Ich habe auch nicht ganz verstanden, wie eine Entprellfunktion 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! Zielfernrohr, Verschlüsse und Co. gut im Griff haben setTimeout Methode hilft.

Nachdem dies gesagt wurde, wird unten die grundlegende Debounce-Funktion erklärt und in meinem Beitrag, auf den oben verwiesen wird, demonstriert.

Das fertige Produkt

// Create JD Object
// ----------------
var JD = {};

// Debounce Method
// ---------------
JD.debounce = function(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 || 200);
        if ( callNow ) { 
            func.apply(context, args);
        }
    };
};

Die Erklärung

// Create JD Object
// ----------------
/*
    It's a good idea to attach helper methods like `debounce` to your own 
    custom object. That way, you don't pollute the global space by 
    attaching methods to the `window` object and potentially run in to
    conflicts.
*/
var JD = {};

// Debounce Method
// ---------------
/*
    Return 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 `wait` milliseconds. If `immediate` is passed, trigger the 
    function on the leading edge, instead of the trailing.
*/
JD.debounce = function(func, wait, immediate) {
    /*
        Declare a variable named `timeout` variable that we will later use 
        to store the *timeout ID returned by the `setTimeout` function.

        *When setTimeout is called, it retuns a numeric ID. This unique ID
        can be used in conjunction with JavaScript's `clearTimeout` method 
        to prevent the code passed in the first argument of the `setTimout`
        function from being called. Note, this prevention will only occur
        if `clearTimeout` is called before the specified number of 
        milliseconds passed in the second argument of setTimeout have been
        met.
    */
    var timeout;

    /*
        Return an anomymous function that has access to the `func`
        argument of our `debounce` method through the process of closure.
    */
    return function() {

        /*
            1) Assign `this` to a variable named `context` so that the 
               `func` argument passed to our `debounce` method can be 
               called in the proper context.

            2) Assign all *arugments passed in the `func` argument of our
               `debounce` method to a variable named `args`.

            *JavaScript natively makes all arguments passed to a function
            accessible inside of the function in an array-like variable 
            named `arguments`. Assinging `arguments` to `args` combines 
            all arguments passed in the `func` argument of our `debounce` 
            method in a single variable.
        */
        var context = this,   /* 1 */
            args = arguments; /* 2 */

        /*
            Assign an anonymous function to a variable named `later`.
            This function will be passed in the first argument of the
            `setTimeout` function below.
        */
        var later = function() {

            /*      
                When the `later` function is called, remove the numeric ID 
                that was assigned to it by the `setTimeout` function.

                Note, by the time the `later` function is called, the
                `setTimeout` function will have returned a numeric ID to 
                the `timeout` variable. That numeric ID is removed by 
                assiging `null` to `timeout`.
            */
            timeout = null;

            /*
                If the boolean value passed in the `immediate` argument 
                of our `debouce` method is falsy, then invoke the 
                function passed in the `func` argument of our `debouce`
                method using JavaScript's *`apply` method.

                *The `apply` method allows you to call a function in an
                explicit context. The first argument defines what `this`
                should be. The second argument is passed as an array 
                containing all the arguments that should be passed to 
                `func` when it is called. Previously, we assigned `this` 
                to the `context` variable, and we assigned all arguments 
                passed in `func` to the `args` variable.
            */
            if ( !immediate ) {
                func.apply(context, args);
            }
        };

        /*
            If the value passed in the `immediate` argument of our 
            `debounce` method is truthy and the value assigned to `timeout`
            is falsy, then assign `true` to the `callNow` variable.
            Otherwise, assign `false` to the `callNow` variable.
        */
        var callNow = immediate && !timeout;

        /*
            As long as the event that our `debounce` method is bound to is 
            still firing within the `wait` period, remove the numerical ID  
            (returned to the `timeout` vaiable by `setTimeout`) from 
            JavaScript's execution queue. This prevents the function passed 
            in the `setTimeout` function from being invoked.

            Remember, the `debounce` method is intended for use on events
            that rapidly fire, ie: a window resize or scroll. The *first* 
            time the event fires, the `timeout` variable has been declared, 
            but no value has been assigned to it - it is `undefined`. 
            Therefore, nothing is removed from JavaScript's execution queue 
            because nothing has been placed in the queue - there is nothing 
            to clear.

            Below, the `timeout` variable is assigned the numerical ID 
            returned by the `setTimeout` function. So long as *subsequent* 
            events are fired before the `wait` is met, `timeout` will be 
            cleared, resulting in the function passed in the `setTimeout` 
            function being removed from the execution queue. As soon as the 
            `wait` is met, the function passed in the `setTimeout` function 
            will execute.
        */
        clearTimeout(timeout);

        /*
            Assign a `setTimout` function to the `timeout` variable we 
            previously declared. Pass the function assigned to the `later` 
            variable to the `setTimeout` function, along with the numerical 
            value assigned to the `wait` argument in our `debounce` method. 
            If no value is passed to the `wait` argument in our `debounce` 
            method, pass a value of 200 milliseconds to the `setTimeout` 
            function.  
        */
        timeout = setTimeout(later, wait || 200);

        /*
            Typically, you want the function passed in the `func` argument
            of our `debounce` method to execute once *after* the `wait` 
            period has been met for the event that our `debounce` method is 
            bound to (the trailing side). However, if you want the function 
            to execute once *before* the event has finished (on the leading 
            side), you can pass `true` in the `immediate` argument of our 
            `debounce` method.

            If `true` is passed in the `immediate` argument of our 
            `debounce` method, the value assigned to the `callNow` variable 
            declared above will be `true` only after the *first* time the 
            event that our `debounce` method is bound to has fired.

            After the first time the event is fired, the `timeout` variable
            will contain a falsey value. Therfore, the result of the 
            expression that gets assigned to the `callNow` variable is 
            `true` and the function passed in the `func` argument of our
            `debounce` method is exected in the line of code below.

            Every subsequent time the event that our `debounce` method is 
            bound to fires within the `wait` period, the `timeout` variable 
            holds the numerical ID returned from the `setTimout` function 
            assigned to it when the previous event was fired, and the 
            `debounce` method was executed.

            This means that for all subsequent events within the `wait`
            period, the `timeout` variable holds a truthy value, and the
            result of the expression that gets assigned to the `callNow`
            variable is `false`. Therefore, the function passed in the 
            `func` argument of our `debounce` method will not be executed.  

            Lastly, when the `wait` period is met and the `later` function
            that is passed in the `setTimeout` function executes, the 
            result is that it just assigns `null` to the `timeout` 
            variable. The `func` argument passed in our `debounce` method 
            will not be executed because the `if` condition inside the 
            `later` function fails. 
        */
        if ( callNow ) { 
            func.apply(context, args);
        }
    };
};

Benutzeravatar von Mulan
Mulan

wir alle verwenden Promises jetzt

Viele Implementierungen, die ich gesehen habe, verkomplizieren das Problem oder haben andere Hygieneprobleme. Wir schreiben das Jahr 2021 und Promises nutzen wir schon lange – und das aus gutem Grund. Promises bereinigen asynchrone Programme und verringern die Möglichkeit, dass Fehler passieren. In diesem Beitrag werden wir unsere eigenen schreiben debounce. Diese Implementierung wird –

  • höchstens ein Promise zu einem bestimmten Zeitpunkt ausstehend haben (pro entprellter Aufgabe)
  • Stoppen Sie Speicherlecks, indem Sie ausstehende Zusagen ordnungsgemäß stornieren
  • Lösen Sie nur das letzte Versprechen auf
  • demonstrieren Sie das richtige Verhalten mit Live-Code-Demos

Wir schreiben debounce mit seinen beiden Parametern, der task zu entprellen, und die Menge an Millisekunden zu verzögern, ms. Wir führen eine einzige lokale Bindung für ihren lokalen Zustand ein, t

function debounce (task, ms) {
  let t = { promise: null, cancel: _ => void 0 }
  return async (...args) => {
    try {
      t.cancel()
      t = deferred(ms)
      await t.promise
      await task(...args)
    }
    catch (_) { /* prevent memory leak */ }
  }
}

Wir sind auf Mehrweg angewiesen deferred Funktion, die ein neues Versprechen erstellt, das in aufgelöst wird ms Millisekunden. Es führt zwei lokale Bindungen ein, die promise selbst, eine Fähigkeit zu cancel es –

function deferred (ms) {
  let cancel, promise = new Promise((resolve, reject) => {
    cancel = reject
    setTimeout(resolve, ms)
  })
  return { promise, cancel }
}

Klickzähler Beispiel

In diesem ersten Beispiel haben wir eine Schaltfläche, die die Klicks des Benutzers zählt. Der Ereignis-Listener wird mit angehängt debouncealso wird der Zähler erst nach einer bestimmten Dauer inkrementiert –

// debounce, deferred
function debounce (task, ms) { let t = { promise: null, cancel: _ => void 0 }; return async (...args) => { try { t.cancel(); t = deferred(ms); await t.promise; await task(...args); } catch (_) { console.log("cleaning up cancelled promise") } } }
function deferred (ms) { let cancel, promise = new Promise((resolve, reject) => { cancel = reject; setTimeout(resolve, ms) }); return { promise, cancel } }

// dom references
const myform = document.forms.myform
const mycounter = myform.mycounter

// event handler
function clickCounter (event) {
  mycounter.value = Number(mycounter.value) + 1
}

// debounced listener
myform.myclicker.addEventListener("click", debounce(clickCounter, 1000))
<form id="myform">
<input name="myclicker" type="button" value="click" />
<output name="mycounter">0</output>
</form>

Beispiel einer Live-Abfrage, “autocomplete”

In diesem zweiten Beispiel haben wir ein Formular mit einer Texteingabe. Unser search Abfrage wird mit angehängt debounce

// debounce, deferred
function debounce (task, ms) { let t = { promise: null, cancel: _ => void 0 }; return async (...args) => { try { t.cancel(); t = deferred(ms); await t.promise; await task(...args); } catch (_) { console.log("cleaning up cancelled promise") } } }
function deferred (ms) { let cancel, promise = new Promise((resolve, reject) => { cancel = reject; setTimeout(resolve, ms) }); return { promise, cancel } }

// dom references
const myform = document.forms.myform
const myresult = myform.myresult

// event handler
function search (event) {
  myresult.value = `Searching for: ${event.target.value}`
}

// debounced listener
myform.myquery.addEventListener("keypress", debounce(search, 1000))
<form id="myform">
<input name="myquery" placeholder="Enter a query..." />
<output name="myresult"></output>
</form>

mehrere Entprellungen, Reaktionshaken useDebounce

In einer anderen Frage und Antwort fragt jemand, ob es möglich ist, den Mechanismus zur Aufhebung der Entprellung verfügbar zu machen und eine zu erstellen useDebounce Haken reagieren. Verwenden deferred oben, es ist eine triviale Übung.

// revised implementation
function debounce(task, ms) {
  let t = { promise: null, cancel: _ => void 0 }
  return [
   // ...,
    _ => t.cancel() // ✅ return cancellation mechanism
  ]
}
// revised usage
const [inc, cancel] = debounce(clickCounter, 1000) // ✅ two controls
myform.mybutton.addEventListener("click", inc)
myform.mycancel.addEventListener("click", cancel)

Implementieren von a useDebounce Reaktionshaken ist ein Kinderspiel –

function useDebounce(task, ms) {
  const [f, cancel] = debounce(task, ms)
  useEffect(_ => cancel) // ✅ auto-cancel when component unmounts
  return [f, cancel]
}

Besuchen Sie das ursprüngliche Q&A für eine vollständige Demo

  • Wie kommt es, dass die Lösung trotzdem funktioniert? t ist innerhalb jeder Funktion lokal? Würde t.cancel() nicht immer nichts tun, weil t nicht zwischen den Funktionen geteilt wird? Als Kontext habe ich Ihr Snippet in meiner Svelte-App verwendet, aber die Versprechen werden nicht abgebrochen (nach der Verzögerung werden ALLE Anrufe aufgelöst). Also machte ich die t global und es hat funktioniert Immer noch positiv bewertet

    – Elton Lin

    15. Juni um 14:24 Uhr


  • Es “funktioniert”, weil debounce gibt a zurück Neu Funktion, die abgeschlossen ist t. Jeder debounced Funktion, die Sie erstellen, hat einen eigenen Verweis auf t. Wenn du machst t global können Sie nicht mehr als eine verwenden debounce pro Seite. Die Versprechen werden definitiv storniert (abgelehnt), wie in den obigen Demos gezeigt. Vielleicht können Sie eine Kopie Ihres Codes teilen, damit ich Ihnen bei der Diagnose des Problems helfen kann?

    – Mulan

    15. Juni um 17:13 Uhr

  • @EltonLin Ich habe dieser Antwort einige Notizen hinzugefügt und eine weitere Frage und Antwort verlinkt, die die Verwendung von Entprellung in einem anspruchsvolleren Beispiel zeigt.

    – Mulan

    15. Juni um 18:17 Uhr

  • Ich werde zuerst gründlich nachdenken und dann mit einem nachdenklicheren Kommentar antworten!

    – Elton Lin

    27. Juni um 1:22

  • Das mag alles schick sein, aber es hat bei mir nicht funktioniert. Die Funktion, die ich übergeben habe, lief immer noch mehrmals und als ich das Timeout erhöhte, war es schlimmer.

    – Post-Impatica

    16. August um 14:54 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Eine einfache Entprellfunktion:

HTML:

<button id='myid'>Click me</button>

Javascript:

    function debounce(fn, delay) {
      let timeoutID;
      return function(...args) {
          if(timeoutID)
            clearTimeout(timeoutID);
          timeoutID = setTimeout(() => {
            fn(...args)
          }, delay);
      }
   }

document.getElementById('myid').addEventListener('click', debounce(() => {
  console.log('clicked');
}, 2000));

  • Wie kommt es, dass die Lösung trotzdem funktioniert? t ist innerhalb jeder Funktion lokal? Würde t.cancel() nicht immer nichts tun, weil t nicht zwischen den Funktionen geteilt wird? Als Kontext habe ich Ihr Snippet in meiner Svelte-App verwendet, aber die Versprechen werden nicht abgebrochen (nach der Verzögerung werden ALLE Anrufe aufgelöst). Also machte ich die t global und es hat funktioniert Immer noch positiv bewertet

    – Elton Lin

    15. Juni um 14:24 Uhr


  • Es “funktioniert”, weil debounce gibt a zurück Neu Funktion, die abgeschlossen ist t. Jeder debounced Funktion, die Sie erstellen, hat einen eigenen Verweis auf t. Wenn du machst t global können Sie nicht mehr als eine verwenden debounce pro Seite. Die Versprechen werden definitiv storniert (abgelehnt), wie in den obigen Demos gezeigt. Vielleicht können Sie eine Kopie Ihres Codes teilen, damit ich Ihnen bei der Diagnose des Problems helfen kann?

    – Mulan

    15. Juni um 17:13 Uhr

  • @EltonLin Ich habe dieser Antwort einige Notizen hinzugefügt und eine weitere Frage und Antwort verlinkt, die die Verwendung von Entprellung in einem anspruchsvolleren Beispiel zeigt.

    – Mulan

    15. Juni um 18:17 Uhr

  • Ich werde zuerst gründlich nachdenken und dann mit einem nachdenklicheren Kommentar antworten!

    – Elton Lin

    27. Juni um 1:22

  • Das mag alles schick sein, aber es hat bei mir nicht funktioniert. Die Funktion, die ich übergeben habe, lief immer noch mehrmals und als ich das Timeout erhöhte, war es schlimmer.

    – Post-Impatica

    16. August um 14:54 Uhr

Benutzeravatar von user12484139
Benutzer12484139

Dies ist eine Variante, die beim ersten Aufruf immer die entprellte Funktion mit aussagekräftigeren Variablennamen auslöst:

function debounce(fn, wait = 1000) {
  let debounced = false;
  let resetDebouncedTimeout = null;
  return function(...args) {
    if (!debounced) {
      debounced = true;
      fn(...args);
      resetDebouncedTimeout = setTimeout(() => {
        debounced = false;
      }, wait);
    } else {
      clearTimeout(resetDebouncedTimeout);
      resetDebouncedTimeout = setTimeout(() => {
        debounced = false;
        fn(...args);
      }, wait);
    }
  }
};

1431550cookie-checkWas ist die “Entprellen”-Funktion in JavaScript?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy