File "debounce.js"
File size: 2.02 KB
MIME-type: text/plain
Charset: utf-8
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;