jQuery / backbone.js - 延迟函数调用

4
我有一个名为#search的元素,当keyup事件发生时应该触发一个函数。这个函数只有在一定时间内没有发生keyup事件(例如500毫秒)时才会触发。这将防止搜索结果在按下每个字母时更新。问题是,在backbone.js中,我的事件是以哈希形式存在的,适用的事件看起来像这样:'keyup #search' : 'setSearch',当keyup事件发生时,它调用setSearch()函数。我现在不太清楚如何处理它。我尝试了各种方法,但没有一种方法可以在函数结束后保持定时器。我大致有以下代码:
setSearch: function(event) {
            var timer = window.setTimeout( function() {
                // run function here
                alert('fired');
            }, 500);
    },

与其使用alert('fired'),我将运行自己的函数。我能理解为什么这段代码无法运行(为每个keyup事件设置了一个计时器)。但我仍不清楚我还能尝试什么。

4个回答

18

你需要的实际上是来自underscore.js(Backbone的要求)提供给你的一个函数。

 setSearch: _.throttle(function() {
                //Do Stuff
              }, 500),

简而言之,这将返回一个新的匿名函数形式,每500毫秒只能被调用一次。您可能需要根据自己的需求调整时间。

更多信息: http://documentcloud.github.com/underscore/#throttle


10
我在项目中遇到了类似的需求。我想补充一点,回应Skylar Anderson关于_.throttle的帖子,实际上我发现_.debounce()对我的需求更加适合。 - Peter O.
去抖动(Debounce)对于这个问题比节流(Throttle)要好得多。 - tonyhb

3
您需要在视图中创建一个实例变量来存储计时器ID,然后您可以根据需要停止和重新启动它:
setSearch: function(event) {
    var self = this;
    if(self.timer)
        clearTimeout(self.timer);
    self.timer = setTimeout(function() {
        alert('fired');
        self.timer = null;
    }, 500);
}

所以,如果计时器已经在运行,您可以调用clearTimeout来停止它,启动一个新的计时器,并将计时器ID存储在self.timer(也称为this.timer)中。您还需要在计时器的回调函数或setSearch中重置存储的计时器ID,在计时器触发一次后它才能继续工作。而所有的self都只是为了捕获this以便在计时器的回调函数中使用。


2
防止在每个 keyup 上更新搜索结果,这正是 Underscore 的 _.debounce(function, wait) 函数所要处理的情况。Underscore 文档中关于 _.debounce() 的说明如下:

创建并返回传递的 function 的新抑制版本,该版本将推迟其执行时间,直到距离上一次调用已经过去了 wait 毫秒。对于实现仅在输入停止到达后才应发生的行为非常有用。

您重新设计的代码看起来会很简单:
setSearch: function(event) {
    _.debounce(doSomething, 300);
},

“which will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked” - 在“搜索字段”的情况下不起作用,因为您不希望它在第一次键盘松开时进行搜索,而是要等待3次键盘松开后再进行搜索-特别是对于大型数据集。但是如果需要触发某些事件然后再等待再次触发,那么这个方法非常好用。 - VeenarM

0

由于您希望事件处理程序能够维护事件是否已经recentlyFired,因此您可能希望将处理程序包装到闭包中并维护该状态。当事件触发时,状态应更改为true,并在500毫秒延迟后重置为false。

setSearch: function( ) {
    var firedRecently = false;
    return function(event) {
        if (firedRecently) {
            // it has fired recently. Do you want to do something here?
        } else {
            // not fired recently
            firedRecently = true;
            // run your function here
            alert('fired');
            var resetStatus = window.setTimeout( function () {
                firedRecently = false;
            }, 500);
        }
    }
}( );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接