Home > Back-end >  Countdown timer issue with multiple timers running unexpectedly resulting in overlapping digits
Countdown timer issue with multiple timers running unexpectedly resulting in overlapping digits

Time:01-13

this may be a small problem, but it seems that I can't find a solution anywhere. I will try to explain the issue the best way I can.

I have a simple timer function:

  let [milliseconds,seconds,minutes] = [0,0,0];
  
  let int = null;
  const start = () => {
    if(int!==null){
      clearInterval(int);
    }
  int = setInterval(displayTimer,10);
  }

  const reset = () => {
    clearInterval(int);
    [milliseconds,seconds,minutes] = [0,0,0];
    document.querySelector('.timerDisplay').innerHTML = '00 : 00';
  }
  
  function displayTimer(){
      milliseconds =10;
      if(milliseconds == 1000){
          milliseconds = 0;
          seconds  ;
          if(seconds == 60){
              seconds = 0;
              minutes  ;
          }
      }
      let m = minutes < 10 ? "0"   minutes : minutes;
      let s = seconds < 10 ? "0"   seconds : seconds;
      document.querySelector('.timerDisplay').innerHTML = `${m} : ${s}`;
  }

And when start and reset functionalities are separated in two different buttons, they work like a charm.

<button onClick={reset} id="pauseTimer">Reset</button>
<button onClick={start} id="startTimer">Start</button>

I am encountering an issue when I try to put both of them in a single function, like this:

  const newGame = () => {
    reset()
    //some other code
    start()
  }

So the newGame function should (in theory) reset the timer and start the new one. Instead, timer resets to zero for a split second, but the "old one" keeps counting, while the new one starts from 00:00, so the numbers overlap. The more I fire newGame, the more overlaps I get.

My question is, how do I prevent this?

I've tried using a useState to store the timer, still didn't work.

Thank you!

CodePudding user response:

I cleaned up your code snippets a bit so I could run it on my machine and it appears to run as expected. If you're still seeing a problem on your end it may be in a piece of code that you didn't share that is somehow interfering with the code you shared.

That said, I saw that you mentioned the useState React hook so I'm assuming you're using React. If that is the case and all of this code is being run inside a React component, then it may be that something you're doing is triggering the component to re-render, which would re-declare new copies of all your local variables and functions. If that's the case, then the reason your old interval is still running is that after the re-render, your reset and start functions are only able to access and interact with the new copies of your local variables that store the current interval and time. I would suggest persisting the state of each of those variables by using the useState React hook

<html>
  <head>
    <script>
      let [milliseconds, seconds, minutes] = [0, 0, 0];

      let int = null;
      const start = () => {
        if (int !== null) {
          clearInterval(int);
        }
        int = setInterval(displayTimer, 10);
      }

      const reset = () => {
        clearInterval(int);
        [milliseconds, seconds, minutes] = [0, 0, 0];
        document.querySelector('.timerDisplay').innerHTML = '00 : 00';
      }

      function displayTimer() {
        milliseconds  = 10;
        if (milliseconds == 1000) {
          milliseconds = 0;
          seconds  ;
          if (seconds == 60) {
            seconds = 0;
            minutes  ;
          }
        }
        let m = minutes < 10 ? "0"   minutes : minutes;
        let s = seconds < 10 ? "0"   seconds : seconds;
        document.querySelector('.timerDisplay').innerHTML = `${m} : ${s}`;
      }

      const newGame = () => {
        reset()
        //some other code
        start()
      }
    </script>
  </head>
  <body>
    <button onClick="reset()" id="pauseTimer">Reset</button>
    <button onClick="start()" id="startTimer">Start</button>
    <button onClick="newGame()" id="newGame">New Game</button>
    <p >00 : 00</p>
  </body>
</html>

CodePudding user response:

One solution to this problem is to wrap the start() function in a setTimeout, so that it waits for a short period of time before creating a new interval. This will give the previous interval enough time to fully clear before a new one is created.

const newGame = () => {
 reset();
setTimeout(start, 50);
}

This way, the reset() function will have enough time to clear the interval, and the start() function will only be called after a 50 milliseconds delay

  • Related