Fossils💻 CodingImplement Throttle
🥚EggJavaScriptPerformancePatterns

Implement Throttle

Throttle ensures a function runs at most once per interval. The implementation reveals understanding of timing and edge cases.

Implement Throttle

Throttle is debounce's counterpart. While debounce waits for silence, throttle guarantees regular execution.

Core Implementation

function throttle(fn, interval) {
  let lastTime = 0;
 
  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      lastTime = now;
      return fn.apply(this, args);
    }
  };
}

Production-Grade Version

function throttle(fn, interval, options = {}) {
  const { leading = true, trailing = true } = options;
  let lastTime = 0;
  let timeoutId = null;
  let lastArgs = null;
  let lastThis = null;
 
  function invoke() {
    lastTime = Date.now();
    const args = lastArgs;
    const ctx = lastThis;
    lastArgs = lastThis = null;
    fn.apply(ctx, args);
  }
 
  function throttled(...args) {
    const now = Date.now();
    const remaining = interval - (now - lastTime);
    lastArgs = args;
    lastThis = this;
 
    if (remaining <= 0 || remaining > interval) {
      if (timeoutId) {
        clearTimeout(timeoutId);
        timeoutId = null;
      }
      if (leading || lastTime !== 0) {
        invoke();
      } else {
        lastTime = now;
      }
    } else if (!timeoutId && trailing) {
      timeoutId = setTimeout(() => {
        timeoutId = null;
        invoke();
      }, remaining);
    }
  }
 
  throttled.cancel = function () {
    clearTimeout(timeoutId);
    timeoutId = null;
    lastArgs = lastThis = null;
    lastTime = 0;
  };
 
  return throttled;
}

When to Use Throttle vs Debounce

ScenarioUse
Search input as user typesDebounce
Scroll position trackingThrottle
Window resize handlerDebounce
Mouse move for dragThrottle
Form validation on changeDebounce
API rate limitingThrottle

Real-World Example

function InfiniteScroll({ onLoadMore }) {
  useEffect(() => {
    const handleScroll = throttle(() => {
      const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
      if (scrollHeight - scrollTop - clientHeight < 200) {
        onLoadMore();
      }
    }, 200);
 
    window.addEventListener('scroll', handleScroll, { passive: true });
    return () => window.removeEventListener('scroll', handleScroll);
  }, [onLoadMore]);
 
  return null;
}

The real interview insight: throttle and debounce are both about controlling execution frequency — they just answer different questions about timing.