Debounce
An implementation
var debounce = function(func, wait) {
var timeout;
// the debounced function
return function() {
var context = this, args = arguments;
// nulls out timer and calls original function
var later = function() {
timeout = null;
func.apply(context, args);
};
// restart the timer to call last function
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
An improvement
If we do add 100 items to a list then we will be clearing and setting a new timer 100 times, yet if these are all added before the end of the event cycle then there isn’t much point resetting a setTimeout 100 times, one should be sufficient.
So now we need to update the debounce so that a timeout is not cleared. What we can do instead is save a timestamp every time we call debounce and only re-initialize a timeout if the last call has a timestamp less than our period in the past.
var debounce = function(func, wait) {
// we need to save these in the closure
var timeout, args, context, timestamp;
return function() {
// save details of latest call
context = this;
args = [].slice.call(arguments, 0);
timestamp = new Date();
// this is where the magic happens
var later = function() {
// how long ago was the last call
var last = (new Date()) - timestamp;
// if the latest call was less that the wait period ago
// then we reset the timeout to wait for the difference
if (last < wait) {
timeout = setTimeout(later, wait - last);
// or if not we can null out the timer and run the latest
} else {
timeout = null;
func.apply(context, args);
}
};
// we only need to set the timer now if one isn't already running
if (!timeout) {
timeout = setTimeout(later, wait);
}
}
};
Results
Then tried our new and improved debounce:
A huge improvement.
*edit* I have created a jsperf calling debounce 100 times here: http://jsperf.com/debounce
You can see it outperforms lodash and underscore mostly due to the fact it only has to install 1 timer rather than remove and install 100 timers. Also the debounce I used for the jsperf is slightly different to the one in the article – it was modified to have the same functionality as underscore and lodash (the ability to execute immediately) to make it a fair test. I have also made a pull request to underscore to change to this implementation and you can see the progress here: https://github.com/jashkenas/underscore/pull/1269
*edit 2*
Looks like lodash has now updated it’s debounce in the edge version (see comments) based on this post! Check out the JSPerf – it’s now VERY fast.
You can get the code for debounce on my github at https://github.com/rhysbrettbowen/debounce
Powered by WPeMatico