UNPKG

debounce

Version:

Delay function calls until a set time elapses after the last invocation

104 lines (80 loc) 2.07 kB
function debounce(function_, wait = 100, options = {}) { if (typeof function_ !== 'function') { throw new TypeError(`Expected the first parameter to be a function, got \`${typeof function_}\`.`); } if (wait < 0) { throw new RangeError('`wait` must not be negative.'); } // TODO: Deprecate the boolean parameter at some point. const {immediate} = typeof options === 'boolean' ? {immediate: options} : options; let storedContext; let storedArguments; let timeoutId; let timestamp; let result; function run() { const callContext = storedContext; const callArguments = storedArguments; storedContext = undefined; storedArguments = undefined; result = function_.apply(callContext, callArguments); return result; } function later() { const last = Date.now() - timestamp; if (last < wait && last >= 0) { timeoutId = setTimeout(later, wait - last); } else { timeoutId = undefined; if (!immediate) { result = run(); } } } const debounced = function (...arguments_) { if ( storedContext && this !== storedContext && Object.getPrototypeOf(this) === Object.getPrototypeOf(storedContext) ) { throw new Error('Debounced method called with different contexts of the same prototype.'); } storedContext = this; // eslint-disable-line unicorn/no-this-assignment storedArguments = arguments_; timestamp = Date.now(); const callNow = immediate && !timeoutId; if (!timeoutId) { timeoutId = setTimeout(later, wait); } if (callNow) { result = run(); } return result; }; Object.defineProperty(debounced, 'isPending', { get() { return timeoutId !== undefined; }, }); debounced.clear = () => { if (!timeoutId) { return; } clearTimeout(timeoutId); timeoutId = undefined; }; debounced.flush = () => { if (!timeoutId) { return; } debounced.trigger(); }; debounced.trigger = () => { result = run(); debounced.clear(); }; return debounced; } // Adds compatibility for ES modules module.exports.debounce = debounce; module.exports = debounce;