Reputation: 32988
I am not quite sure what the technical term for this is. I have a GUI with interactive graphics. After the user has interacted with the GUI, I need to perform some CPU intensive action. However, user input is very frequent, so I only want to call the function after e.g. 1000ms of no userinput. Below the pattern that I use:
scheduler = (function(){
var timer;
function exec(call, delay){
clearTimeout(timer);
timer = setTimeout(call, delay);
};
return exec;
})()
I.e. if the 3 calls to scheduler
are done right after each other, only the final one will actually be executed:
scheduler(function(){alert('foo')}, 1000);
scheduler(function(){alert('bar')}, 1000);
scheduler(function(){alert('zoo')}, 1000);
It seems to work, but it feels a bit hacky I am a little worried about any caveats of Javascript setTimeout
, especially the scoping problems. Does this seem like a reliable pattern I could use on a larger scale? Will the inline function that I pass to scheduler
be able to lookup all objects in its lexical scope as usual, when it is called by settimeout
? What about if I have several of these scheduler instances? Could they interfere with each other? Is there an alternative way of accomplishing this?
Upvotes: 6
Views: 266
Reputation: 32988
The debounce
function in underscore.js does exactly this:
debounce
_.debounce(function, wait, [immediate])
Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: rendering a preview of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on.
Upvotes: 1
Reputation: 2916
In theory, your solution looks like it will work. There are no scoping problems related to you passing a callback function to your scheduler
function; the callback will close over whatever environment it was created in, just like any other function in JavaScript. That being said, scoping rules can be a bit tricky in JavaScript, so make sure that you read up on it.
In practice, there may be some browser-specific issues related to setTimeout
that may make this solution unworkable. For example, the frequency at which certain browsers execute setTimeout
callbacks may vary such that you'll be waiting longer than you expect for a callback to be executed. All setTimeout
callbacks will be executed sequentially; they'll never be executed in parallel. However, you have guarantees as to what order they will be executed in.
All that being said, any major gotcha in your solution will likely have more to do with the callbacks that your registering rather than the way in which you're registering them.
Upvotes: 1
Reputation: 3281
What I would do:
http://jsfiddle.net/gunderson/4XXQ4/1/
var severQueue = [];
var delay;
$("#inputSquare").mousemove(onMouseMove);
function onMouseMove(){
if (delay){
clearTimeout(delay);
}
serverQueue.push("doSomething")
delay = setTimeout(sendToServer, 1000);
}
function sendToServer(){
console.log(serverQueue.length);
delay = null;
$("#inputSquare").addClass("activated");
// do some ajax using serverQueue
// we'll just simulate it with another timeout
for (var i in serverQueue){
serverQueue.pop();
}
onComplete = setTimeout(onAjaxComplete, 1000);
}
function onAjaxComplete(){
$("#inputSquare").removeClass("activated");
}
Upvotes: 1
Reputation: 35829
You could opt for using web worker threads instead:
https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers http://www.html5rocks.com/en/tutorials/workers/basics/
Upvotes: 1