Search code examples
javascriptdebouncing

Debouncing function firing immediately


I am trying to make the code inside updateValidation function work after 800ms but it's firing immediately. This code was working well in procedural coding but looks like it does not like OOP:

eventListeners(){
        document.querySelector('.main_width').addEventListener('input', e => {
            let alertMsgBox = document.querySelector('.height_alert_msg');
            let alertMsg = document.querySelector('.height_alert_msg span');
            
            // let check = ;
            this.debounce(
                this.updateValidation( e.target.value, 12, 41, alertMsgBox, alertMsg, 'str_height' ), 800
             )
        });
    }

    updateValidation( value, min, max, alertEl, alertMsg, param ){
        let message;

        console.log('works');
        if( value > max ){
            alertEl.classList.add('active');
            
            if( param == 'str_height' ){
                message = "Can't be over 41 ft";
            }
            
            alertMsg.innerText = message;
        } else if( value < min ){
            alertEl.classList.add('active');
            
            if( param == 'str_height' ){
                message = "Can't be below 12 ft";
            }
            
            alertMsg.innerText = message;
        } else {
            alertEl.classList.remove('active');
            alertMsg.innerText = '';            
        }
    }
    
    debounce(func, delay){
        let timeout;
        
        return (...args) => {
            clearTimeout(timeout);
            timeout = setTimeout( () => {
                func(...args)
            }, delay)
        }
    }

Solution

  • Your debounce method is supposed to take a function, and returns a (wrapped) function that can be called in place of it. You're calling debounce with the result of calling your method immediately. Check the difference between the two below examples using your debounce code

    function debounce(func, delay) {
      let timeout;
    
      return (...args) => {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          func(...args)
        }, delay)
      }
    }
    
    function test(msg) {
      console.log(msg, new Date());
    }
    
    console.log("time start", new Date());
    
    debounce(test("Wrong usage - will run immediately!"), 1000);
    
    var debouncedTest = debounce(test, 1000);
    debouncedTest("Correct usage - will run after 1s");

    You can fix your code as follows:

    document.querySelector('.main_width').addEventListener('input', debounce(e => {
        let alertMsgBox = document.querySelector('.height_alert_msg');
        let alertMsg = document.querySelector('.height_alert_msg span');
        this.updateValidation( e.target.value, 12, 41, alertMsgBox, alertMsg, 'str_height' );
    }, 800);
    

    Edit: You still seem a little confused how this function works. Hopefully this snippet might make it a bit clearer. The purpose of a debounce function is to stop the wrapped method firing too often. The below example writes the content of the textbox to the console, but only after you stop typing for 1 second:

    function debounce(func, delay) {
      let timeout;
    
      return (...args) => {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          func(...args)
        }, delay)
      }
    }
    
    document.getElementById("debouncedBox").addEventListener("input", debounce(e => {
        console.log(e.target.value);
    },1000));
    <input id="debouncedBox">