1

I have written a countdown 24 hours timer but it is slow and sometimes the difference time between my system clock and the timer reach to 2 hours. i would like to know if there is an alternative for setinterval and i place it inside my code.

var _tick = setInterval(function() {
    if ((remSeconds) > 0) {
      if (hoursCounter > 0) {
        if (minutesCounter == 0 && secondsCounter == 0) {
          minutesCounter = 60;
          hoursCounter = hoursCounter - 1;
        }
      }
      if (secondsCounter == 0) {
        secondsCounter = 60;
        minutesCounter = minutesCounter - 1;
      }
      secondsCounter = secondsCounter - 1;
      remSeconds = remSeconds - 1;

      $seconds.text(formatNumber(secondsCounter));
      $minutes.text(formatNumber(minutesCounter));
      $hours.text(formatNumber(hoursCounter));
    } else {
      clearInterval(_tick);
      document.getElementById("tRemaining").innerHTML = "EXPIRED";
    }
  },
  1000);
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
user3683666
  • 75
  • 12
  • 4
    The `1000` milliseconds interval is not very accurate over many iterations. If you're going to create a countdown timer, you need to read a reliable clock for each iteration to ensure you don't drift. This answer summarizes it nicely: https://stackoverflow.com/a/985692/1024832 – Marc Sep 13 '19 at 20:16
  • 7
    `setInterval` is fine, but don't rely on the actual interval durations. So don't use a counter. Instead read the system clock each time with the `Date` constructor or `Date.now()` – trincot Sep 13 '19 at 20:17
  • 2
    I agree with trincot. Unless you have an absolute requirement of seeing every single second's numbers, use setInterval and get the time from the Date object. – ControlAltDel Sep 13 '19 at 20:21
  • 1
    As @Marc said, `1000` isn't super accurate over time and this becomes an issue because you're manually counting down. Work out the countdown date, by like adding 24 hrs to the current `Date` when you start, and then work out the difference in time between 'now' and the end of the timer, every `1000` milliseconds. So use setInterval to decide when to update the display, but don't use it to actually count time, use some sort of `new Date()` comparison for that. – Brett East Sep 13 '19 at 20:21

2 Answers2

2

You could do this like that:

var startTime = Date.now();
var duration = 1000*60*60*24;  // set duration to 24h

var _tick = setInterval(function() {
   let remSeconds = Math.floor((duration - (Date.now()-startTime))/1000);
   if ((remSeconds) > 0) {
      let remHours = Math.floor(remSeconds/3600);
      remSeconds -= remHours*3600;
      let remMins = Math.floor(remSeconds/60);
      remSeconds -= remMins*60;
      document.getElementById("tRemaining").innerHTML = remHours+':'+remMins+':'+remSeconds;
   } 
   else {
      clearInterval(_tick);
      document.getElementById("tRemaining").innerHTML = "EXPIRED";
   }
},
1000);
<div id="tRemaining"></div>

If you want a clean output, you need to also add something to take care of 0 padding, to avoid things like 23:7:31, but the essential is there.

François Huppé
  • 2,006
  • 1
  • 6
  • 15
-1
const mainFunc = () => {
    console.log('Call')
    setTimeout(() => {
        mainFunc()

    },4000)

};
mainFunc();
  • 2
    Why do you think that this code wouldn't suffer form the same problems `setInterval` has for the OP. `4000` is the least amount of time that will past for the timeout, but it can be much longer, so the time will also diverge. – t.niese May 16 '23 at 10:32