Mark As Completed Discussion

Solution

During implementation, the first thing to consider is how we prevent multiple function calls from executing. A very simple way is by using a boolean flag, like isThrottling, to check if we should execute the block. It can be initialized as false, and during the first execution of a function, we can set it to true. Then, the next time the function is invoked, nothing will happen.

JAVASCRIPT
1function throttle(func, waitTime) {
2  let isThrottling = false;
3
4  return () => {
5    if (!isThrottling) {
6      // run the code
7      func.apply(this);
8      isThrottling = true;
9    }
10  };
11}

But of course, this will set the isThrottling flag to true, and all future calls will run into this issue and not execute:

JAVASCRIPT
1const testCall = throttle(() => console.log("it will run once"));
2testCall(); // it will run once
3testCall(); // undefined

We'll need to programmatically reset the flag after a certain time. The most obvious way to do this is to use the setTimeout method to flip the boolean after a certain amount of time. Let's add this on.

JAVASCRIPT
1function throttle(func, waitTime) {
2  let isThrottling = false;
3
4  return () => {
5    if (!isThrottling) {
6      // Run the code
7      func.apply(this);
8      isThrottling = true;
9
10      // Queue up timer to flip the flag so future iterations can occur
11      function queueTimer() {
12        setTimeout(() => {
13          isThrottling = false;
14        }, waitTime);
15      }
16      queueTimer();
17    }
18  };
19}

We're now at a point where we've wrapped the function in a closure that manipulates the isThrottling flag. The flag will prevent any other calls from executing until a certain time period has passed. Now let's start wrapping this up by making sure the function is indeed invoked again after the waitTime finishes.

One other thing we haven't considered-- what happens in the event that the user invokes the functon during the throttling period, using different arguments? We want to save that call and wait the allotted time before executing. To do this, we'll need to save the new arguments in a savedArgs method.

Please follow the comments to see what's happening:

JAVASCRIPT
1function throttle(func, waitTime) {
2  // Set isThrottling flag to false to start
3  // and savedArgs to null
4  let isThrottling = false,
5    savedArgs = null;
6  // Spread the arguments for .apply
7  return function (...args) {
8    // Return a wrapped function
9    // Flag preventing immediate execution
10    if (!isThrottling) {
11      // Actual initial function execution
12      func.apply(this, args);
13      // Flip flag to throttling state
14      isThrottling = true;
15      // Queue up timer to flip the flag so future iterations can occur
16      function queueTimer() {
17        setTimeout(() => {
18          // Stop throttling
19          isThrottling = false;
20          // Queueing up the next invocation after wait time passes
21          if (savedArgs) {
22            func.apply(this, savedArgs);
23            isThrottling = true;
24            savedArgs = null;
25            queueTimer();
26          }
27        }, waitTime);
28      }
29      queueTimer();
30    }
31    // Wait state until timeout is done
32    // Save arguments
33    else savedArgs = args;
34  };
35}