Lodash的反跳功能在匿名函数中不起作用


70

您好,我似乎无法弄清楚为什么将反跳功能直接传递给keyup事件时会按预期工作;但是如果我将其包装在匿名函数中则无法使用。

我有这个问题的小提琴:http : //jsfiddle.net/6hg95/1/

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

的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不触发反跳功能;但是最后一个function会开火。我不明白为什么会这样。有人可以帮我理解吗?

编辑 好,所以在#exeDebouncedFunc(您引用的那个)中不发生反跳的原因是因为该函数是在匿名函数的范围内执行的,另一个keyup事件将在另一个匿名范围内创建一个新函数;从而在您键入某些内容时多次触发去抖动功能(而不是一次触发,这是预期的行为;请参见#function)。

能否请您解释之间的差异#anonFunction#function。这又是一个范围界定问题的原因,为什么其中一个起作用而另一个不起作用?

编辑 好的,现在我知道为什么会这样了。这就是为什么我需要将其包装在匿名函数中的原因:

小提琴: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/>');
    }
})();

Answers:


67

正如Palpatim解释的那样,原因在于_.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
+1进行解释。基本上这$('#function').on('keyup', _.debounce(debounceIt, 500, false)); //This is working. 是: 为什么要去抖动返回功能。像这样美丽,而Just Makes Sense™
Metagrapher

43

轻松思考

_.debounce返回一个反跳功能!因此,与其以

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

您宁愿调用去抖动功能

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

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

2
如果我必须调用多个函数keyup并且应该仅对其中一个进行去抖动该怎么办?
bharadhwaj

41

debounce 不执行该函数,它将返回内置了防抖功能的函数。

退货

(功能):返回新的去抖动功能。

因此,您的#function处理程序实际上是在做正确的事情,方法是返回一个供jQuery用作键处理程序的函数。为了修正您的#noReturnAnonFunction示例,您可以在函数的上下文中简单地执行去抖动的函数:

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

但是,这会在您的去抖动周围引入不必要的匿名函数包装器。


17
这么多投票,但是恕我直言,这行不通。在每次键入键时,功能debounceIt都会被转换为一个反抖动功能并立即执行,其效果是debounceIt将延迟500ms。每次按键都会重复一次!因此,最后,您的代码等效于$('#noReturnAnonFunction')。on('keyup',function(){setTimeout(debounceIt,500);})没有反跳...只是延迟。
zevero

你是对的。我不认为这是反弹。延迟了
vuquanghoang

6

您可以像这样返回去抖功能:

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

在这种情况下,似乎不需要这样做。相似的想法在另一种情况下对我有所帮助。
2017年

_.debounce不返回该函数,而是将其设置为超时的时间。
fungusanthrax

根据文档_.debounce确实返回了该函数。参考 lodash.com/docs/#debounce
Sunil Sharma

0

更一般而言,如果您希望以尾随行为来消除抖动(帐户的最终点击或更可能是选定输入的最后一次更改),以及有关首次点击/更改的视觉反馈,则您将面临相同的问题。

这不起作用:

$(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));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.