throttle returns a wrapper that runs fn at most once per limit milliseconds. Unlike debounce, calls during the cooldown are dropped rather than deferred — so the first call in a burst wins instead of the last.
export function throttle<T extends (...args: unknown[]) => void>(
fn: T,
limit: number,
): (...args: Parameters<T>) => void {
let lastCall = -Infinity;
return (...args: Parameters<T>) => {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
fn(...args);
}
};
}
When to reach for it
- Scroll-position trackers that only need to update every ~100ms.
- High-frequency mousemove handlers driving cheap visual updates.
- Rate-limiting analytics events from rapid user interactions.