debounce-throttle-utils
Version:
A lightweight utility library that provides debounce and throttle functions to optimize performance by controlling the execution frequency of functions.
107 lines (89 loc) • 3.42 kB
text/typescript
type Fn = (...args: any[]) => void;
interface DebounceOptions {
leading?: boolean; // Execute on the leading edge
trailing?: boolean; // Execute on the trailing edge
}
interface ThrottleOptions {
leading?: boolean; // Execute on the leading edge
trailing?: boolean; // Execute on the trailing edge
}
/**
* Debounce function - Delays the execution of the passed function until the user stops calling it for a specified delay.
*
* @param func The function to debounce
* @param delay The time to wait before executing the function, in milliseconds
* @param options The options for leading/trailing execution
* @returns A debounced function
*/
function debounce(func: Fn, delay: number, options: DebounceOptions = {}): Fn & { cancel: () => void } {
let timer: NodeJS.Timeout;
let lastCallTime = 0;
// Use a normal function here to access `this` context
const debouncedFn = function (this: any, ...args: any[]) {
const context = this; // Explicitly refer to the correct `this` value
const now = Date.now();
const isLeading = options.leading && !lastCallTime;
clearTimeout(timer);
if (isLeading) {
func.apply(context, args); // Apply with the correct context and arguments
}
timer = setTimeout(() => {
if (options.trailing) {
func.apply(context, args); // Apply with the correct context and arguments
}
lastCallTime = now;
}, delay);
};
// Cancel the pending debounced function execution
debouncedFn.cancel = function () {
clearTimeout(timer);
};
return debouncedFn;
}
/**
* Throttle function - Ensures the passed function is executed at most once in a given period of time.
*
* @param func The function to throttle
* @param limit The time interval in milliseconds to limit the execution of the function
* @param options The options for leading/trailing execution
* @returns A throttled function with flush method
*/
function throttle(func: Fn, limit: number, options: ThrottleOptions = {}): Fn {
let lastFunc: NodeJS.Timeout;
let lastTime: number = 0;
let lastArgs: any[] = []; // Store the arguments to use in flush
// Use a normal function here to access `this` context
const throttledFn = function (this: any, ...args: any[]) {
const context = this; // Explicitly refer to the correct `this` value
const now = Date.now();
const isLeading = options.leading && !lastTime;
if (isLeading) {
func.apply(context, args); // Apply with the correct context and arguments
lastTime = now;
}
const remainingTime = limit - (now - lastTime);
if (remainingTime <= 0) {
clearTimeout(lastFunc);
func.apply(context, args); // Apply with the correct context and arguments
lastTime = now;
} else if (options.trailing) {
clearTimeout(lastFunc);
lastFunc = setTimeout(() => {
func.apply(context, args); // Apply with the correct context and arguments
lastTime = Date.now();
}, remainingTime);
}
// Store the latest arguments for flushing
lastArgs = args;
};
// Flush the pending throttled function execution
throttledFn.flush = function () {
if (lastFunc) {
clearTimeout(lastFunc);
func.apply(this, lastArgs); // Apply with the correct context and the stored arguments
}
};
return throttledFn;
}
// Exporting the debounce and throttle functions
export { debounce, throttle };