-2

I am using the code for accurate timer from this post: https://stackoverflow.com/a/29972322/17490329

but I modified it to be a countdown timer.

I want that when the countdown ends, it will stop, but using clearTimeout in my case doesn't work:

let duration = 5; // seconds
countdownTimer(duration);

function countdownTimer (duration) {
    let interval = 1000; // milliseconds 
    let expected = Date.now() + interval;
    let timeoutHandler;

    setTimeout(step, interval);
    function step() {
        let dt = Date.now() - expected;
        if (dt > interval) {

        }
        console.log(duration);

        expected += interval;

        duration--;
        if (duration <= 0) {            
            clearTimeout(timeoutHandler); // doesn't stop the timer
        }
        timeoutHandler = setTimeout(step, Math.max(0, interval - dt)); // take into account drift
    }
}

Why?

pileup
  • 1
  • 2
  • 18
  • 45

2 Answers2

2

let duration = 5; // seconds
countdownTimer(duration);

function countdownTimer (duration) {
    let interval = 1000; // milliseconds 
    let expected = Date.now() + interval;
    let timeoutHandler;

    setTimeout(step, interval);
    function step() {
        let dt = Date.now() - expected;
        if (dt > interval) {

        }
        console.log(duration);

        expected += interval;

        duration--;
        if (duration <= 0) {            
            clearTimeout(timeoutHandler); // doesn't stop the timer
            return; //don't forget to stop executing function
        }
        timeoutHandler = setTimeout(step, Math.max(0, interval - dt)); // take into account drift
    }
}

inside of "if" condition you miss "return" to stop executing fucntion

1

using clearTimeout in my case doesn't work

It works, but then you execute the setTimeout() again, so if you put last line before the if condition you'll get what you want:

let duration = 5; // seconds
countdownTimer(duration);

function countdownTimer (duration) {
    let interval = 1000; // milliseconds 
    let expected = Date.now() + interval;
    let timeoutHandler;

    setTimeout(step, interval);
    
    function step() {
        let dt = Date.now() - expected;
        if (dt > interval) {

        }
        console.log(duration);

        expected += interval;
        duration--;
        
        timeoutHandler = setTimeout(step, Math.max(0, interval - dt));
        
        if (duration <= 0) {            
            clearTimeout(timeoutHandler); // doesn't stop the timer
        }
    }
}
Cody Tookode
  • 862
  • 12
  • 22
  • Or use else... `if (duration > 0) clearTimeout(timeoutHandler); else timeoutHandler = setTimeout(step, Math.max(0, interval - dt));` – mplungjan Jun 07 '23 at 13:11