Debounce returns a function, that, as long as it continues to be invoked, will not be triggered.
/**
* Debounce
*
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for N
* milliseconds. If `immediate` is passed, trigger the function on the leading
* edge, instead of the trailing.
*
* @example
*
* var myEfficientFn = debounce(function() {
* // All the taxing stuff you do
* }, 250);
*
* window.addEventListener('resize', myEfficientFn);
*
* @param {Function} func The function to invoke.
* @param {Number} wait time after it stops being called for N milliseconds.
* @param {Boolean} Immediately trigger the function on the leading edge,
* instead of the trailing.
*
* @return {Function}
*/
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
}, wait);
if (immediate && !timeout) {
func.apply(context, args);
}
};
}
// -------------------------------------
// More advanced version from https://github.com/component/debounce
// -------------------------------------
/**
* Returns a function, that, as long as it continues to be invoked, will not be
* triggered. The function will be called after it stops being called for N
* milliseconds. If `immediate` is passed, trigger the function on the leading
* edge, instead of the trailing. The function also has a property 'clear' that
* is a function which will clear the timer to prevent previously scheduled
* executions.
*
* @api public
* @source underscore.js
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
*
* @param {Function} function to wrap
* @param {Number} timeout in ms (`100`)
* @param {Boolean} whether to execute at the beginning (`false`)
*
* @example
* var debounce = require('debounce');
*
* window.onresize = debounce(resize, 200);
*
* function resize(e) {
* console.log('height', window.innerHeight);
* console.log('width', window.innerWidth);
* }
*
* // To later clear the timer and cancel currently scheduled executions:
* window.onresize.clear();
*
* // To execute any pending invocations and reset the timer:
* window.onresize.flush();
*/
function debounce(func, wait, immediate) {
var timeout, args, context, timestamp, result;
if (null == wait) wait = 100;
function later() {
var last = Date.now() - timestamp;
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
context = args = null;
}
}
}
var debounced = function () {
context = this;
args = arguments;
timestamp = Date.now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
debounced.clear = function () {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
};
debounced.flush = function () {
if (timeout) {
result = func.apply(context, args);
context = args = null;
clearTimeout(timeout);
timeout = null;
}
};
return debounced;
}
// Adds compatibility for ES modules
debounce.debounce = debounce;
module.exports = debounce;