mplungjan
mplungjan

Reputation: 178403

Plain JS countdown with repeat and delay

I keep running into several issues when creating a countdown script

  1. it does not run smoothly
  2. hard to make it repeat (closure)
  3. hard to delay the start and to delay the repeat (closure)

Can someone please help me FIX this code which should work in my opinion but doesn't

the processing I need is

a. counter starts delay number of seconds after the page loads,
b. when counter reaches 0, the countdown RE-starts after delay number of seconds

Here is my Fiddle

Issues:

  1. when it starts, the counter seems to wait an additional second before counting down
  2. it does not pause
  3. the repeat starts after the counter has continued

.

// more accurate timer - https://gist.github.com/1185904
function interval(duration, fn){
  this.baseline = undefined

  this.run = function(){
    if(this.baseline === undefined){
      this.baseline = new Date().getTime()
    }
    fn()
    var end = new Date().getTime()
    this.baseline += duration

    var nextTick = duration - (end - this.baseline)
    if(nextTick<0){
      nextTick = 0
    }
    (function(i){
        i.timer = setTimeout(function(){
        i.run(end)
      }, nextTick)
    }(this))
  }

  this.stop = function(){
   clearTimeout(this.timer)
  }
}
window.onload=function() {
  var cnt1 = 10;
  var delay1 = 5;
  var timer1 = new interval(1000, function(){
    document.getElementById('out1').innerHTML=cnt1--
    if (cnt1 <= 0) { // trying to reset
      timer1.stop(); // does not work
      cnt1 = 10;
      setTimeout(function() { timer1.run()},delay1*1000)
    }
  })
  setTimeout(function() { timer1.run()},delay1*1000)
}  

Upvotes: 0

Views: 1119

Answers (2)

davin
davin

Reputation: 45565

Object exposing start([delay]) and stop().

http://jsfiddle.net/RVBDQ/3/

function interval(duration, fn, delay){
    this.timer = null;
    this.duration = duration;
    this.fn = fn;

    this.start(delay);
}
interval.prototype.start = function(delay){
    if (this.timer) {return;}
    var self=this;
    this.timer = setTimeout(function(){ self.run(); }, delay||0);
};
interval.prototype.run = function(called){
    var self = this,
        nextTick = called ? this.duration - (new Date - called) : 0;

    this.timer = setTimeout(function(){
        self.fn();
        self.run(new Date);
    }, nextTick<0 ? 0 : nextTick);
};
interval.prototype.stop = function(){
    clearTimeout(this.timer);
    this.timer = null;
};

window.onload = function() {
    var cnt1 = 10;
    var delay1 = 5;
    window.timer1 = new interval(1000, function(){
        document.getElementById('out1').innerHTML=cnt1;
        cnt1 = cnt1 === 1 ? 10 : cnt1-1;
    }, delay1*1000);
};

Upvotes: 1

Rob W
Rob W

Reputation: 349252

I've rewritten your code to produce the desired results. Your previous code was very inefficient. See my script comments for usage.

Fiddle: http://jsfiddle.net/RVBDQ/1/

/*
  @name  timer
  @param number startFrom     Starts counting down from this number
  @param number delay         Seconds to wait before repeating the counter
  @param number intervalDelay Milliseconds between countdown
  @param number runTimes      Optional; Limit of counting. The function stops when it has run <runTimes> times. Default 1 (=one countdown)
  @param Boolean noFirstRun   Optional; If false, the counter starts off immediately. Default false
*/

function timer(startFrom, delay, intervalDelay, runTimes, notFirstRun){
    if(typeof runTimes == "undefined") runTimes = 1;
    if(runTimes-- < 0) return;
    setTimeout(function(){
        var ctn = startFrom;
        var timer1 = window.setInterval(function(){
            document.getElementById('out1').innerHTML = ctn--;
            if(ctn <= 0){
                clearInterval(timer1);
                timer(startFrom, delay, intervalDelay, runTimes, true);
            }

        }, intervalDelay);
    }, notFirstRun?delay*1000:0);
}
window.onload=function() {
    timer(10, 5, 1000, 2);
    //Runs two times, starts counting from 10 to 1, delays 5 seconds between counters.
}  

Upvotes: 2

Related Questions