lodash debounce funktioniert nicht in anonymer Funktion

70

Hallo, ich kann anscheinend nicht herausfinden, warum die Entprellungsfunktion wie erwartet funktioniert, wenn sie direkt an ein Keyup-Ereignis übergeben wird. aber es funktioniert nicht, wenn ich es in eine anonyme Funktion einbinde.

Ich habe Probleme mit dem Problem: http://jsfiddle.net/6hg95/1/

EDIT: Alle Dinge hinzugefügt, die ich versucht habe.

HTML

<input id='anonFunction'/>
<input id='noReturnAnonFunction'/>
<input id='exeDebouncedFunc'/>
<input id='function'/>
<div id='output'></div>

JAVASCRIPT

$(document).ready(function(){
    $('#anonFunction').on('keyup', function () {
        return _.debounce(debounceIt, 500, false); //Why does this differ from #function
    });
    $('#noReturnAnonFunction').on('keyup', function () {
        _.debounce(debounceIt, 500, false); //Not being executed
    });
    $('#exeDebouncedFunc').on('keyup', function () {
        _.debounce(debounceIt, 500, false)(); //Executing the debounced function results in wrong behaviour
    });
    $('#function').on('keyup', _.debounce(debounceIt, 500, false)); //This is working.
});

function debounceIt(){
    $('#output').append('debounced');
}

anonFunctionund noReturnAnonFunctionlöst die Entprellungsfunktion nicht aus; aber der letzte functionfeuert. Ich verstehe nicht, warum das so ist. Kann mir bitte jemand helfen, das zu verstehen?

BEARBEITEN Ok, der Grund dafür, dass das Entprellen in #exeDebounceFunc (dem, auf das Sie verweisen) nicht erfolgt, liegt darin, dass die Funktion im Bereich der anonymen Funktion ausgeführt wird und ein anderes Keyup-Ereignis eine neue Funktion in einem anderen anonymen Bereich erstellt. also die entprellte Funktion so oft auslösen, wie Sie etwas eingeben (anstatt einmal zu feuern, was das erwartete Verhalten wäre; siehe unten #function)?

Können Sie bitte den Unterschied zwischen #anonFunctionund erklären #function. Geht es hier wieder darum, warum einer von ihnen funktioniert und der andere nicht?

EDIT Ok, jetzt verstehe ich, warum das passiert. Und hier ist, warum ich es in eine anonyme Funktion einwickeln musste:

Geige: http://jsfiddle.net/6hg95/5/

HTML

<input id='anonFunction'/>
<div id='output'></div>

JAVASCRIPT

(function(){
    var debounce = _.debounce(fireServerEvent, 500, false);

    $('#anonFunction').on('keyup', function () {
        //clear textfield
        $('#output').append('clearNotifications<br/>');
        debounce();
    });

    function fireServerEvent(){
        $('#output').append('serverEvent<br/>');
    }
})();
Kristian Barrett
quelle

Antworten:

67

Wie Palpatim erklärte, liegt der Grund in der Tatsache, dass _.debouce(...)eine Funktion zurückgegeben wird, die beim Aufrufen ihre Magie entfaltet.

Daher haben Sie in Ihrem #anonFunctionBeispiel einen Schlüssel-Listener, der beim Aufrufen nur eine Funktion an den Aufrufer zurückgibt, die nichts mit den Rückgabewerten des Ereignis-Listeners tut.

Dies ist ein Ausschnitt aus der _.debounce(...)Definition:

_.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);
      };
      if (immediate && !timeout) func.apply(context, args);
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  } 

Ihr wichtiger Ereignis-Listener muss die zurückgegebene Funktion von aufrufen _.debounce(...), oder Sie können wie in Ihrem nicht anonymen Beispiel die vom _.debounce(...)Aufruf zurückgegebene Funktion als Ereignis-Listener verwenden.

Michael Dahl
quelle
2
+1 für diese Erklärung. Grundsätzlich gilt: $('#function').on('keyup', _.debounce(debounceIt, 500, false)); //This is working. WARUM Debounce eine Funktion zurückgibt. Es ist so schön und macht einfach Sinn ™
Metagrapher
42

Denken Sie einfacher

_.debounce gibt eine entprellte Funktion zurück! Also anstatt in Begriffen zu denken

$el.on('keyup'), function(){
   _.debounce(doYourThing,500); //uh I want to debounce this
}

Sie rufen stattdessen lieber die entprellte Funktion auf

var doYourThingDebounced = _.debounce(doYourThing, 500); //YES, this will always be debounced

$el.on('keyup', doYourThingDebounced);
Zevero
quelle
2
Was ist, wenn ich mehrere Funktionen aufrufen muss keyupund nur eine davon entprellt werden soll?
Bharadhwaj
41

debounce führt die Funktion nicht aus, sondern gibt eine Funktion mit der darin enthaltenen Debounciness zurück.

Kehrt zurück

(Funktion) : Gibt die neue entprellte Funktion zurück.

Ihr #functionHandler macht also tatsächlich das Richtige, indem er eine Funktion zurückgibt, die von jQuery als Keyup-Handler verwendet wird. Um Ihr #noReturnAnonFunctionBeispiel zu korrigieren, können Sie die entprellte Funktion einfach im Kontext Ihrer Funktion ausführen:

$('#noReturnAnonFunction').on('keyup', function () {
    _.debounce(debounceIt, 500, false)(); // Immediately executes
});

Aber das führt einen unnötigen anonymen Funktions-Wrapper um Ihre Entprellung ein.

Palpatim
quelle
17
So viele positive Stimmen, aber imho kann das nicht funktionieren. Bei jeder Eingabe wird die Funktion debounceIt in eine entprellte Funktion umgewandelt UND sofort ausgeführt, so dass sich debounceIt um 500 ms verzögert. Dies wird bei jedem Tastendruck wiederholt! Am Ende entspricht Ihr Code also $ ('# noReturnAnonFunction'). On ('keyup', function () {setTimeout (debounceIt, 500);}) Kein Entprellen ... nur Verzögerung.
Zevero
Du hast recht. Ich glaube nicht, dass es entprellt. Es verzögert sich
vuquanghoang
6

Sie können die Entprellungsfunktion wie folgt zurückgeben:

(function(){
    var debounce = _.debounce(fireServerEvent, 500, false);

    $('#anonFunction').on('keyup', function () {
        //clear textfield
        $('#output').append('clearNotifications<br/>');
        return debounce();
    });

    function fireServerEvent(){
        $('#output').append('serverEvent<br/>');
    }
})();
jiv-e
quelle
Es scheint, dass dies in dieser Situation nicht erforderlich ist. Eine ähnliche Idee hat mir jedoch in einer anderen Situation geholfen.
Jiv-E
_.debounce gibt die Funktion nicht zurück, sondern die Zeit, für die das Timeout eingestellt ist.
Pilzanthrax
Laut Dokumentation gibt _.debounce die Funktion zurück. ref. lodash.com/docs/#debounce
Sunil Sharma
0

Wenn Sie eine Entprellung mit einem nachlaufenden Verhalten (Konten für den letzten Klick oder wahrscheinlicher die letzte Änderung an einer ausgewählten Eingabe) und ein visuelles Feedback für den ersten Klick / die erste Änderung wünschen, sind Sie im Allgemeinen mit demselben Problem konfrontiert.

Das funktioniert nicht:

$(document).on('change', "#select", function() {
    $('.ajax-loader').show();
    _.debounce(processSelectChange, 1000);
});

Dies wäre eine Lösung:

$(document).on('change', "#select", function() {
    $('.ajax-loader').show();
});
$(document).on('change', "#select", _.debounce(processSelectChange, 1000));
Baishu
quelle