Skip to content
Advertisement

why does the event listener in this throttling function behave like that?

While I was learning about throttling in javascript, I came upon an event-listener behavior that I can’t explain. Here is a simple throttling function.

const btn=document.querySelector("#throttle"); 
      
    // Throttling Function 
    const throttleFunction=(func, delay)=>{ 
      
      // Previously called time of the function 
      let prev = 0;  
      console.log(prev); //This gets called only once and it is even before the button is clicked
      return (...args) => { 
        // Current called time of the function 
        let now = new Date().getTime();  
  
        // Logging the difference between previously  
        // called and current called timings 
        console.log(now-prev, delay);  //This however doesn't get called before the button is clicked
          
        // If difference is greater than delay call 
        // the function again. 
        if(now - prev> delay){  
          prev = now; 
  
          // "..." is the spread operator here  
          // returning the function with the  
          // array of arguments 
          return func(...args);   
        } 
      } 
    } 
    btn.addEventListener("click", throttleFunction(()=>{ 
      console.log("button is clicked") 
    }, 1500)); 
<button id="throttle">Click Me</button> 

I have two questions.

  1. Why does let prev = 0; only get called once? i.e why doesn’t prev get reset to 0 every time the function is called?
  2. I have also noticed that let prev = 0; gets called before the button is even clicked, Why does this happen? and why doesn’t the rest of the function get called before the button is clicked as well?

This is where I found the code above. I have looked into addEventListener on MDN but to no avail. Any help would be appreciated.

Advertisement

Answer

The .addEventListener() method takes a reference to a function as its second argument, which it can invoke when your button is clicked. So something like this will fail to add the function as a click event handler:

const sayHello = () => console.log("hello");
btn.addEventListener("click", sayHello());

In the above example JavaScript:

  1. Sees the call to addEventListener()

  2. Evaluates its arguments, which means calling the sayHello() function.

    2.1. sayHello() runs and returns undefined

  3. Calls the addEventListener() method with "click" and undefined (the evaluated arguments)

Above the sayHello() is a function call, so it will execute as your event listener is added and before any clicks occur, resulting in the return value of sayHello being used as the second argument to addEventListener(), so the above code will evaluate to something like:

const sayHello = () => console.log("hello");
btn.addEventListener("click", undefined);

To correctly pass a reference to the event listener, you would need to pass a function that can then later be invoked by JS when a click occurs:

btn.addEventListener("click", sayHello);

With that in mind, your throttleFunction() argument is being called when you add your event listener, which means that the throttleFunction itself isn’t what is being passed as the second argument to addEventListener(), but rather the return value. This may be a little clearer if you extract the callback to throttleFunction:

const fn = () => {console.log("button is clicked")};
// invoking the `throttleFunction` function with `()`
const clickHandler = throttleFunction(fn, 1500);
btn.addEventListener("click", clickHandler); // clickHandler is a reference to a function (a non-invoked/called function)

Since your throttleFunction() function is being invoked, the returned function from throttleFunction is being used as the argument for addEventListener(), not the throttleFunction itself. The returned function is only then executed when a click occurs. As a result, let prev = 0; is executed once when the throttleFunction is first called which is when click event listener is added, but the returned function is executed multiple times, as JS will call it only when you click on your button.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement