49 lines
1.4 KiB
TypeScript
49 lines
1.4 KiB
TypeScript
/**
|
|
* Throttles a function to limit execution frequency
|
|
*
|
|
* Ensures a function executes at most once per `wait` milliseconds.
|
|
* Unlike debounce, throttled functions execute on the leading edge
|
|
* and trailing edge if called repeatedly.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const logScroll = throttle(() => {
|
|
* console.log('Scroll position:', window.scrollY);
|
|
* }, 100);
|
|
*
|
|
* window.addEventListener('scroll', logScroll);
|
|
* // Will log at most once every 100ms
|
|
* ```
|
|
*
|
|
* @param fn - Function to throttle
|
|
* @param wait - Minimum time between executions in milliseconds
|
|
* @returns Throttled function
|
|
*/
|
|
export function throttle<T extends (...args: any[]) => any>(
|
|
fn: T,
|
|
wait: number,
|
|
): (...args: Parameters<T>) => void {
|
|
let lastCall = 0;
|
|
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
return (...args: Parameters<T>) => {
|
|
const now = Date.now();
|
|
const timeSinceLastCall = now - lastCall;
|
|
|
|
if (timeSinceLastCall >= wait) {
|
|
lastCall = now;
|
|
fn(...args);
|
|
} else {
|
|
// Schedule for end of wait period (trailing edge)
|
|
if (timeoutId) {
|
|
clearTimeout(timeoutId);
|
|
}
|
|
timeoutId = setTimeout(() => {
|
|
lastCall = Date.now();
|
|
fn(...args);
|
|
timeoutId = null;
|
|
}, wait - timeSinceLastCall);
|
|
}
|
|
};
|
|
}
|