简体   繁体   中英

clearTimeout not working: parameter undefined(even though it's defined in the global scope)

My setTimeout() function works, but my clearTimeout() is not working. Even though I have an 'if' statement that's supposed to run the clearTimeout function once my variable 'secs' is less than 0, the timer keeps counting down into negative numbers. When I type my variable name, 'secs' into the console, I get undefined, even though it's defined as a parameter in the function called by my setTimeout. I don't know what I'm doing wrong. Can anyone help, please?

My full code is at https://codepen.io/Rburrage/pen/qBEjXmx ;

Here's the JavaScript snippet:

function startTimer(secs, elem) {
    t = $(elem);
    t.innerHTML = "00:" + secs;

    if(secs<0) {
        clearTimeout(countDown);
    }
    secs--;
    //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

}

Add a condition to call recursive function like below.

if (secs < 0) {

   secs = secsInput;
 }

   //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

For a countdown timer, I would recommend using setInterval and clearInterval instead. setInterval will repeatedly run the callback function for you. It might look like this:

let countdown;

function startTimer(secs, elem) {
  countdown = setInterval(function(){
    t = $(elem);
    t.innerHTML = "00:" + secs;

    secs--
    if (secs < 0) {
      clearInterval(countdown);
    }
  }, 1000);
}

In your case, it's more convenient to use setInterval and clearInterval .

To keep the setTimeout and clearTimeout functions, you should add return in the if statement.

function startTimer(secs, elem) {
    t = $(elem);
    t.innerHTML = "00:" + secs;

    if(secs<0) {
        clearTimeout(countDown);
        return;
    }
    secs--;
    //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

}

By the time you call clearTimeout(countDown) , countDown refers to the previous timeout, that already timed out. It will not stop the one yet to start. You could just not re set the timeout, like

 if(!/*finished*/) setTimeout(startTimer, 1000, secs, elem);

So there are 4 events in my opinion that will have to be addressed by the timer:

  1. The quiz starts
  2. The quiz ends
  3. The timer runs out
  4. The player answers a question

This can be solved by a function returning an object with some options. The createTimer can be used to set the parameters for the timer.

Point 1. would be timer.start() --> will start a timer with the parameters

Point 3. can be addressed with the callback that will be called if the timer runs out --> createTimer(5,'display', ()=>{ // your code goes here })

Point 2. can be achieved with --> timer.stop()

Point 4. is needed when the timer needs to be reset without running out timer.reset()

Further on the interval is not in the global scope so you could have multiple timers with different settings and they wouldn't interfere with each other

// function for creating the timer
function createTimer(seconds, cssSelector, callbackOnTimeout) {
    // interval the timer is running
    let interval;
    // the html node where innerText will be set
    const display = document.getElementById(cssSelector)
    // original seconds passt to createTimer needed for restart
    const initSec = seconds

    // starting or continuing the interval
    function start() {

        // setting interval to the active interval
        interval = setInterval(() => {

            display.innerText = `00:${seconds}`;

            --seconds;
            if (seconds < 0) {
                // calling restart and callback to restart
                callbackOnTimeout()
                restart()
            }
        }, 1000);

    }

    // just stopping but not resetting so calling start will continue the timer
    // player takes a break
    function stop(){
        clearInterval(interval)
    }

    // opted for a restart and not only a reset since it seemed more appropriate for your problem
    function restart(){
        clearInterval(interval)
        seconds = initSec
        start()
    }
    // returning the object with the functions
    return {
        start: start,
        stop:   stop,
        restart:  restart
    }
}

// example for creating a timer
const timer1 = createTimer(5,'display',()=>{
    console.log(`you where to slow ohhh...`)
})

// calling the timer
timer1.start()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM