Evgenia Karunus
Evgenia Karunus

Reputation: 11202

Javascript: restarting countdown timer doesn't work as I expect it to

I am making a countdown timer that should be reseting and starting anew every 10 seconds. This is the code I came up with by now:

function count(){
    var end_date = new Date().getTime()+10*1000;
    setInterval(function(){
      var current_date = new Date().getTime();
      var seconds_left = parseInt((end_date - current_date) / 1000);
      document.getElementById("countdown").innerHTML = seconds_left + " seconds ";
    }, 1000);
}

setInterval(function(){count()}, 10*1000);

It is supposed to function as follows:
+ I set interval that will restart count() every 10 seconds.
+ count() defines end_date - a date 10 seconds from now.
+ then count() sets interval that will restart every 1 second.
+ every 1 second seconds_left variable is changed according to how current_date changed with respect to end_date.
+ as soon as seconds_left becomes 0, setInterval from step 1 fires and starts count() anew.

Which step am I implementing the wrong way? Do I misunderstand the functioning of setInterval()? Here is my JsFiddle: http://jsfiddle.net/sy5stjun/ .

Upvotes: 0

Views: 178

Answers (2)

David
David

Reputation: 3763

My guess is that each call is in its own new object and you get multiple instances of itself fighting ever 10 seconds.

Using your approach using date objects here is a possible re-write:

var tmr = null;
var time;

function bigInterval() {
    clearInterval(tmr);
    time = (new Date()).valueOf() + (10 * 1000);
    smallInterval();
    tmr = setInterval(smallInterval, 500);
}

function smallInterval() {
    var cur = (new Date()).valueOf();
    var seconds_left = parseInt((time - cur) / 1000);
    document.getElementById("countdown").innerHTML = seconds_left + " seconds";
}

bigInterval();
setInterval(bigInterval, 10*1000);

In the above code I've updated the small timer to be 500ms instead of 1000ms as it won't exactly line up with the system clock at 1000 and you get visual jumps in the numbers.

If exact timing isn't 100% important then here is a possible shorter method:

var t = 10;

setInterval(function() {
    document.getElementById("countdown").innerHTML = t + " seconds";
    t--;
    if (t <= 0) {
        t = 10;
    }
}, 1000);

Upvotes: 1

Jason M. Batchelor
Jason M. Batchelor

Reputation: 2951

There are a few things going on, here. You're not specific why you have to set another interval inside your loop, but there are a lot easier ways to accomplish what you're going for. Another approach follows:

HTML:

<!-- string concatenation is expensive in any language. 
     Only update what has to change to optimize -->
<h1 id='countdown'><span id="ct"></span> seconds </h1>

JS:

// For one thing, grabbing a new reference to the 
// dom object each interval is wasteful, and could interfere with
// timing, so get it outside your timer, and store it in a var scoped
// appropriately.
var ct = document.getElementById("ct");
// set your start
var ctStart = 10;
// set your counter to the start
var ctDown = ctStart;

var count = function() {
    // decrement your counter
    ctDown = ctDown - 1;
    // update the DOM
    ct.innerHTML = ctDown;
    // if you get to 0, reset your counter
    if(ctDown == 0) { ctDown = ctStart; }
};

// save a reference to the interval, in case you need to cancel it
// Also, you only need to include a reference to the function you're
// trying to call, here. You don't need to wrap it in an anonymous function
var timer = window.setInterval(count, 1000);

My jsFiddle available for tinkering, here: http://jsfiddle.net/21d7rf6s/

Upvotes: 1

Related Questions