【问题标题】:How do I reuse this JavaScript timeout closure?如何重用这个 JavaScript 超时闭包?
【发布时间】:2011-07-22 04:52:45
【问题描述】:

我找到了以下用于实现超时的 JavaScript 代码(可能在 Stack Overflow 上?):

var delay = (function() {
  var timer = 0;
  return function(callback, ms) {
    clearTimeout(timer);
    timer = setTimeout(callback, ms);
  };
})();

我是 JavaScript 新手,所以我仍在尝试围绕闭包。如果我在一个地方调用delay(firstCallback, 200),然后立即调用delay(secondCallback, 200),则第一个超时回调被清除,而第二个回调成功执行。

如何在不同的实例中重复使用delay 而不会覆盖其他实例? (不确定这些术语是否正确,但希望它能理解我的意思。)因此,在上面的示例中,我希望两个回调都执行。

感谢您的帮助!

编辑:作为一个实际示例,我正在尝试在输入字段上缓冲按键事件,以便仅在 200 毫秒内未按下任何键后执行回调。但是我有多个输入字段,目前当两个输入字段快速连续发生按键事件时,缓冲区会中断。

【问题讨论】:

    标签: javascript timeout closures settimeout


    【解决方案1】:

    闭包保持在内部函数调用之间持续存在的状态。在这种情况下,使用它,因此一次只有一个超时。如果你想一次有多个超时可用,你可以写

    setTimeout(callback, ms);
    

    编辑:

    对于您的示例,最好的解决方案是制作这样的对象

    function DelayManager(){}
    DelayManager.prototype.timer = 0;
    DelayManager.prototype.delay = function(callback, ms) {
      clearTimeout(this.timer);             
      this.timer = setTimeout(callback, ms);   
    }
    someDelayManager = new DelayManager();
    

    您将使用每个输入元素唯一的某个对象的成员变量而不是 someDelayManager。要添加延迟,您可以调用。

    someDelayManager.delay(callback, ms);
    

    【讨论】:

    • 好的,有道理。但是我怎样才能编写一个可重用的延迟函数呢?例如,对于按键缓冲,我只想在 200ms 没有按键时执行回调,每次按键时都需要使用 clearTimeout。我不想跟踪ID,调用clearTimeout,然后到处调用setTimeout。
    【解决方案2】:

    要重用它,摆脱匿名函数并将其用作生成器会更容易。

    var createDelayManager = function() {
      var timer = 0;
      return function(callback, ms) {
         clearTimeout(timer);
         timer = setTimeout(callback, ms);
      };
    }
    
    
    var delayManagerOne = createDelayManager();
    delayManagerOne(firstCallback, 200);
    
    var delayManagerTwo = createDelayManager();
    delayManagerTwo(secondCallback, 200);
    

    这是一个有效的小提琴: http://jsfiddle.net/HJrM7/

    但是,值得注意的是,这个闭包的目的是防止多个回调叠加到某个对象上。这是一个非常好的闭包,尽管它使您能够确保最后触发的事件将是被执行的事件。我经常使用这种技术来防止在 ie 重绘期间出现闪烁或不需要的鼠标移出事件。

    【讨论】:

    • 防止多个回调堆积在某个对象上正是我想要防止的,但我有多个对象要防止这种情况发生。使用 new 是理想的方式,还是我应该从根本上改变我拥有的延迟关闭代码?
    • 你错了。您的代码不正确。首先,您在没有参数的情况下调用 delay(因此您会收到带有 undefined 参数的 setTimeout 调用)。第二,你写delayManagerOne(firstCallback, 200)——这应该怎么做?你确定,你了解闭包吗?如果您的代码是正确的,那么您仍在使用相同的closured 变量timer
    • 有了这个紧凑的闭包,我认为你不会从重新编码中获得任何性能优势。在这种情况下,您实际上并不需要新函数,因为每次调用延迟时,当您说 return function() {} 时,您实际上是在返回一个新函数,所以只需 var delayManagerOne = delay();应该可以正常工作。 delay() 在这里真的是一个生成器。
    • @orangutancloud:我不想冒犯你并挑战你的编程技能。但是你的代码是错误的。 timer 在这里不是delay 的成员,它已被关闭。所以无论如何你不能使用问题中的代码创建timer var 的新实例。而且你不能给delay 0 个参数。
    • @artyon.stv 你是对的,我读代码太快了。 delay 实际上是一个匿名函数,而我将它作为生成器阅读。
    【解决方案3】:

    你正在寻找

    Delay = function(callback, ms) {
        this.callback = callback;
        this.ms = ms;
    };
    
    Delay.prototype = {
        timer: -1,
    
        restart: function() {
            if (this.timer != -1) clearTimeout(this.timer);
            this.timer = setTimeout(this.callback, this.ms);
        }
    };
    
    var delay1 = new Delay(callback1, 100);
    var delay2 = new Delay(callback2, 100);
    
    // on some event1
    delay1.restart();
    
    // on some event2
    delay2.restart();
    

    jsfiddle 示例:http://jsfiddle.net/TF9Tw/1/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多