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