问题
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.
回答1:
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.
回答2:
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/
回答3:
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);
来源:https://stackoverflow.com/questions/5420776/how-do-i-reuse-this-javascript-timeout-closure