在匿名函数中不起作用

您好,我似乎不能弄清楚为什么当直接传递到 keyup 事件时,deounce 函数能够正常工作; 但是如果我将它包装在一个匿名函数中,它就不能正常工作。

我已经解决了这个问题: http://jsfiddle.net/6hg95/1/

编辑: 添加了我试过的所有东西。

超文本标示语言

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

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

anonFunctionnoReturnAnonFunction不触发退出函数,但最后一个 function触发。我不明白为什么会这样。有人能帮我理解一下吗?

剪辑 好的,那么在 # exeDeboucedFunc (你引用的那个)中没有发生退出的原因是因为函数是在匿名函数的作用域中执行的,而另一个 keyup 事件将在另一个匿名作用域中创建一个新函数; 因此,当你键入一些东西时,多次触发退出的函数(而不是触发一次,这将是预期的行为; 参见 #function之前) ?

你能解释一下 #anonFunction#function的区别吗。这又是一个范围问题,为什么其中一个工作,而另一个不?

剪辑 现在我明白为什么会这样了。这就是为什么我需要把它封装在一个匿名函数中:

小提琴: http://jsfiddle.net/6hg95/5/

超文本标示语言

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

JAVASCRIPT (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/>');
}
})();
110173 次浏览

debounce doesn't execute the function, it returns a function with the debounciness built into it.

Returns

(Function): Returns the new debounced function.

So your #function handler is actually doing the Right Thing, by returning a function to be used by jQuery as a keyup handler. To fix your #noReturnAnonFunction example, you could simply execute the debounced function in the context of your function:

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

But that's introducing a needless anonymous function wrapper around your debounce.

As Palpatim explained, the reason lies in the fact that _.debounce(...) returns a function, which when invoked does its magic.

Therefore in your #anonFunction example, you have a key listener, which when invoked does nothing but return a function to the invoker, which does nothing with the return values from the event listener.

This is a snippet of the _.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);
};
}

Your key event listener must invoke the returned function from _.debounce(...), or you can do as in your non-anonymous example and use the returned function from the _.debounce(...) call as your event listener.

More generally, if you want a debounce with a trailing behaviour (accounts for last click, or more likely last change on a select input), and a visual feedback on first click/change, you are faced with the same issue.

This does not work:

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

This would be a solution:

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

You can return the debounce function like this:

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

Think easier

_.debounce returns a debounced function! So instead of thinking in terms of

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

you rather call the debounced function instead

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


$el.on('keyup', doYourThingDebounced);

Came across this while looking for a solution to calling a debounce with a trailing call, found this article which really helped me: https://newbedev.com/lodash-debounce-not-working-in-react specifically:

Solution for those who came here because throttle / debounce doesn't work >with FunctionComponent - you need to store debounced function via useRef():

export const ComponentName = (value = null) => {
const [inputValue, setInputValue] = useState(value);


const setServicesValue = value => Services.setValue(value);


const setServicesValueDebounced = useRef(_.debounce(setServicesValue, 1000));


const handleChange = ({ currentTarget: { value } }) => {
setInputValue(value);
setServicesValueDebounced.current(value);
};


return <input onChange={handleChange} value={inputValue} />;
};