Skip to content
Advertisement

Understanding debounce function logic flow, particularly for Event object – where does (…args) get it’s values from?

I’m working through a Javascript course and am working with the following code. I understand almost all of it but I’m struggling with following and understanding the logic flow through the code, particularly for the event objects and I want to make sure I’m super clear on this before continuing.

Almost the exact same question has been asked here by someone else with the same confusion but I can’t make sense of any answers unfortunately.

Here’s what I do understand so far:

A key gets pressed -> The debounce function returns (and runs) with parameters func and delay. The func parameter passed in is the onInput function in this case, (which as I understand it, gets an event object returned to it automatically (by Javascript) when the addEventListener fires).

However, onInput is run nested inside the debounce function with func.apply(null, args); so I’m confused as to how the event objects get created and passed through the flow of the code when keys are pressed?

My main question following from this, is how or where does return (...args) within the debounce get its spread parameters from?

Doesn’t the debounce function get passed the event object in this case and not onInput? If so, how does onInput get access to the event object?

Here’s the code:

const fetchData = async (searchTerm) => {
    const response = await axios.get('http://www.omdbapi.com/', {
        params: {
            apikey: '6459bge8',
            s: searchTerm
        }
    });

    console.log(response.data);
};

const input = document.querySelector('input');


const debounce = (func, delay) => {
    let timeoutId;
  
//Where is ...args getting it's values from?
    return (...args) => {
        console.log(args);
      
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        timeoutId = setTimeout(() => {
            func.apply(null, args);
        }, delay);
    };
};

const onInput = (evt) => {
    fetchData(evt.target.value);
  };
  
input.addEventListener('input', debounce(onInput, 500));

Also I can’t make sense of when I comment out the code within the returned function like this:

const debounce = (func, delay) => {
    let timeoutId;
  
    return (...args) => {
        console.log(args);
      
        // if (timeoutId) {
        //     clearTimeout(timeoutId);
        // }
        // timeoutId = setTimeout(() => {
        //     func.apply(null, args);
        // }, delay);
    };
};

The passed in func never runs but the console.log(args) still shows InputEvents in the console when a key is pressed suggesting the args are coming from elsewhere and not set by func.apply(null, args);?

Advertisement

Answer

The main thing to understand with your code is that the addEventListener() function isn’t in charge of calling the debounce() function. The debounce() function is called when the addEventListener gets added to the input element, not when the input event occurs. This is because calling debounce() invokes the function, passing whatever it returns as the second argument to addEventListener(). With that in mind, you function can be re-written as this:

const inputHandler = debounce(onInput, 500); // debounce returns a function
input.addEventListener('input', inputHandler); // the returned function is used in the addEventListener function

So the function that is returned by debounce() is called when an input occurs (not the debounce function itself, as this is called when the addEventListener() method is called, which is immediately when the interpreter meets this line and not when an input occurs).

Doesn’t the debounce function get passed the event object in this case and not onInput? If so, how does onInput get access to the event object?

With the above explanation in mind, the returned function from debounce() is what gets passed as the second argument to addEventListener(). As a result, the returned function acts as the callback and gets passed the event object, which it has accesses to through ...args. In the code-block above, that means inputHanlder gets passed the event object when it gets invoked by JS when an input event occurs. So debounce() never gets passed the event argument, it’s the inner returned function that gets access to the event argument.

As the returned function (ie: the inner function in your code example), gets passed the event object, it can access it via args. The inner function then invokes/calls the onInput function with the event object using func.apply(null, args);.


As for your last example, the func function never runs as it is never called anywhere. It is passed into your function, but it never gets invoked/executed (unlike in the first example where it does get called using .apply()). The InputEvent still gets logged though, as the addEventListener() is what invokes the callback returned when the input occurs. As a result, the inner function still has access to the event object.

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