Throttle function (companion ke debounce)
Throttle execute max 1x per interval. Berbeda dengan debounce yang tunggu pause. Pakai untuk scroll, mousemove, resize.
Dipublikasikan 1 Juni 2026
Saya pernah publish snippet debounce. Ini companion: throttle.
Beda:
- Debounce: tunggu user berhenti, baru execute (search box).
- Throttle: execute max 1x per interval (scroll progress bar).
Kode
/**
* Throttle function — execute max 1x per interval.
* @template {(...args: any[]) => any} F
* @param {F} fn - Function to throttle.
* @param {number} wait - Interval (ms).
* @param {object} [options]
* @param {boolean} [options.trailing=true] - Trigger trailing call after last invoke.
* @returns {F & { cancel: () => void }}
*/
function throttle(fn, wait, options = {}) {
let lastCall = 0;
let timer = null;
let lastArgs = null;
let lastThis = null;
const { trailing = true } = options;
const throttled = function (...args) {
const now = Date.now();
const remaining = wait - (now - lastCall);
lastArgs = args;
lastThis = this;
if (remaining <= 0 || remaining > wait) {
// First call atau lebih dari wait sejak last call
if (timer) {
clearTimeout(timer);
timer = null;
}
lastCall = now;
fn.apply(this, args);
} else if (!timer && trailing) {
// Schedule trailing call
timer = setTimeout(() => {
lastCall = Date.now();
timer = null;
if (lastArgs) {
fn.apply(lastThis, lastArgs);
lastArgs = null;
lastThis = null;
}
}, remaining);
}
};
throttled.cancel = () => {
if (timer) clearTimeout(timer);
timer = null;
lastCall = 0;
lastArgs = null;
};
return throttled;
}
Pemakaian
// Update progress bar saat scroll
const updateProgress = throttle(() => {
const scrollPct = window.scrollY / (document.body.scrollHeight - window.innerHeight);
document.getElementById('progress').style.width = `${scrollPct * 100}%`;
}, 16); // 60fps cap
window.addEventListener('scroll', updateProgress, { passive: true });
// Tracking analytics scroll depth (max 1x per 5 detik)
const trackScrollDepth = throttle(() => {
analytics.track('scroll_depth', { pct: Math.round(scrollPct * 100) });
}, 5000);
window.addEventListener('scroll', trackScrollDepth, { passive: true });
// Resize handler
const onResize = throttle(() => {
recalculateLayout();
}, 200);
window.addEventListener('resize', onResize);
Throttle vs Debounce: cara pilih
| Skenario | Use |
|---|---|
| Live search query | Debounce 300ms |
| Scroll progress bar | Throttle 16ms (60fps) |
| Scroll-based lazy load | Throttle 200ms |
| Auto-save document | Debounce 2000ms |
| Window resize handler | Throttle 100ms |
| Mouse move tracking | Throttle 16ms |
| Form validation (live) | Debounce 500ms |
| Track scroll depth (analytics) | Throttle 5000ms |
Catatan
{ passive: true }padaaddEventListeneruntuk scroll/touch events — kasih browser permission optimize.- Throttle
wait=16= 60fps. Untuk smooth animation, ini batas atas. PertimbangkanrequestAnimationFrameuntuk visual animation. - Pakai
cancel()di React useEffect cleanup atau Vue onBeforeUnmount untuk avoid memory leak.
Lodash punya
_.throttleyang sudah matang. Snippet ini untuk yang gak mau dep tambahan.
# tags
throttleperformanceeventsvanilla
Ditulis oleh Asti Larasati · 1 Juni 2026