简体   繁体   中英

How do I reuse this JavaScript timeout closure?

I found the following piece of JavaScript code (maybe here at Stack Overflow?) for implementing a timeout:

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

I'm new to JavaScript, so I'm still trying to wrap my head around closures. If I call delay(firstCallback, 200) in one place and then delay(secondCallback, 200) right after, the first timeout callback is cleared, while the second callback executes successfully.

How do I reuse delay in different instances without overwriting other instances? (Not sure if those terms are correct, but hopefully it gets my point across.) So, in the above example, I want both callbacks to execute.

Thanks for your help!

EDIT: As a practical example, I'm trying to buffer keypress events on an input field, so that the callback is only executed after no key has been pressed for 200ms. But I have multiple input fields, and currently the buffer breaks when two input fields have keypress events in quick succession.

To reuse this, it is easier to get rid of the anonymous function and use it as a generator.

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

Here is a working fiddle: http://jsfiddle.net/HJrM7/

But, It is worth noting, that the point of this closure is to prevent multiple callbacks from getting stacked against some object. It is a really nice closure though that enables you to make sure that the last event triggered will be the one that gets acted on. I use this technique a lot to prevent flickering, or unwanted mouse out events during ie redraws.

You are looking for

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

Example on jsfiddle: http://jsfiddle.net/TF9Tw/1/

The closure holds state that persists between calls of the inner function. In this case it is used so there is only one timeout at a time. If you want multiple timeouts available at a time you may just write

setTimeout(callback, ms);

edit:

For your example, the best solution would be to make an object like this

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

Where instead of someDelayManager you would use a member variable of some object unique per input element. To add a delay you would then call.

someDelayManager.delay(callback, ms);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM