Lodash debounce не работает в анонимной функции

Здравствуйте, я не могу понять, почему функция debounce работает так, как ожидалось, когда передается непосредственно в событие keyup; но он не работает, если я оберну его внутри анонимной функции.

У меня есть проблема: http://jsfiddle.net/6hg95/1/

EDIT: добавлены все, что я пробовал.

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');
}

anonFunction и noReturnAnonFunction не срабатывает функция debounce; но последний function срабатывает. Я не понимаю, почему это так. Может ли кто-нибудь помочь мне понять это?

ИЗМЕНИТЬ Итак, причина в том, что debounce не происходит в #exeDebouncedFunc (тот, который вы ссылаетесь) заключается в том, что функция выполняется в области анонимной функции, а другое событие keyup создаст новую функцию в другой анонимной области; тем самым уволив дебютирующую функцию столько раз, сколько вы набираете что-то (вместо того, чтобы стрелять один раз, что было бы ожидаемым поведением, см. beviour #function)?

Не могли бы вы объяснить разницу между #anonFunction и #function. Это опять же вопрос о том, почему один из них работает, а другой нет?

ИЗМЕНИТЬ Хорошо, теперь я понимаю, почему это происходит. И вот почему мне нужно было обернуть его внутри анонимной функции:

Fiddle: 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/>');
    }
})();

Ответ 1

Как объяснил Палпатим, причина кроется в том, что _.debouce(...) возвращает функцию, которая при вызове делает ее волшебной.

Поэтому в вашем примере #anonFunction у вас есть прослушиватель клавиш, который при вызове ничего не возвращает, кроме как возвращает функцию вызывающему, которая ничего не делает с возвращаемыми значениями из прослушивателя событий.

Это фрагмент определения _.debounce(...):

_.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);
    };
  } 

Ваш слушатель ключевых событий должен вызывать возвращаемую функцию из _.debounce(...), или вы можете сделать это как в своем неанонимном примере, а использовать возвращаемую функцию из вызова _.debounce(...) в качестве вашего прослушивателя событий.

Ответ 2

debounce не выполняет функцию, она возвращает функцию с встроенным в нее debounciness.

Возвращает

(Функция): возвращает новую отмененную функцию.

Итак, ваш обработчик #function на самом деле делает правильную вещь, возвращая функцию, которая будет использоваться jQuery в качестве обработчика клавиатуры. Чтобы исправить ваш пример #noReturnAnonFunction, вы можете просто выполнить функцию debounced в контексте вашей функции:

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

Но это представляет ненужную анонимную оболочку функции вокруг вашего debounce.

Ответ 3

Подумайте проще

_.debounce возвращает отмененную функцию! Поэтому вместо того, чтобы думать в терминах

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

вместо этого вы вместо этого

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

$el.on('keyup'), function(){
   ...
   doYourThing();
   ...
}

Ответ 4

Вы можете вернуть функцию debounce следующим образом:

(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/>');
    }
})();

Ответ 5

В более общем плане, если вам нужен дебют с конечным поведением (учетные записи для последнего клика или, скорее, последнее изменение на входе выбора) и визуальная обратная связь при первом щелчке/изменении, вы сталкиваетесь с той же проблемой.

Это не работает:

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

Это будет решение:

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