en.javascript.info/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md

1.2 KiB

function throttle(func, ms) {

  let isThrottled = false,
    savedArgs,
    savedThis;

  function wrapper() {

    if (isThrottled) { // (2)
      savedArgs = arguments;
      savedThis = this;
      return;
    }

    func.apply(this, arguments); // (1)

    isThrottled = true;

    setTimeout(function() {
      isThrottled = false; // (3)
      if (savedArgs) {
        wrapper.apply(savedThis, savedArgs);
        savedArgs = savedThis = null;
      }
    }, ms);
  }

  return wrapper;
}

A call to throttle(func, ms) returns wrapper.

  1. During the first call, the wrapper just runs func and sets the cooldown state (isThrottled = true).
  2. In this state all calls memorized in savedArgs/savedThis. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
  3. ...Then after ms milliseconds pass, setTimeout triggers. The cooldown state is removed (isThrottled = false). And if we had ignored calls, then wrapper is executed with last memorized arguments and context.

The 3rd step runs not func, but wrapper, because we not only need to execute func, but once again enter the cooldown state and setup the timeout to reset it.