javascripttimercountdowncountdowntimer

How to write a countdown timer in JavaScript?


Just wanted to ask how to create the simplest possible countdown timer.

There'll be a sentence on the site saying:

"Registration closes in 05:00 minutes!"

So, what I want to do is to create a simple js countdown timer that goes from "05:00" to "00:00" and then resets to "05:00" once it ends.

I was going through some answers before, but they all seem too intense (Date objects, etc.) for what I want to do.


Solution

  • I have two demos, one with jQuery and one without. Neither use date functions and are about as simple as it gets.

    Demo with vanilla JavaScript (version with a start/stop button here)

    function startTimer(duration, display) {
        var timer = duration, minutes, seconds;
        setInterval(function () {
            minutes = parseInt(timer / 60, 10);
            seconds = parseInt(timer % 60, 10);
    
            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;
    
            display.textContent = minutes + ":" + seconds;
    
            if (--timer < 0) {
                timer = duration;
            }
        }, 1000);
    }
    
    window.onload = function () {
        var fiveMinutes = 60 * 5,
            display = document.querySelector('#time');
        startTimer(fiveMinutes, display);
    };
    <body>
        <div>Registration closes in <span id="time">05:00</span> minutes!</div>
    </body>

    Demo with jQuery (version with a start/stop button here)

    function startTimer(duration, display) {
        var timer = duration, minutes, seconds;
        setInterval(function () {
            minutes = parseInt(timer / 60, 10);
            seconds = parseInt(timer % 60, 10);
    
            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;
    
            display.text(minutes + ":" + seconds);
    
            if (--timer < 0) {
                timer = duration;
            }
        }, 1000);
    }
    
    jQuery(function ($) {
        var fiveMinutes = 60 * 5,
            display = $('#time');
        startTimer(fiveMinutes, display);
    });
    

    However if you want a more accurate timer that is only slightly more complicated: (version with a start/stop button here)

    function startTimer(duration, display) {
        var start = Date.now(),
            diff,
            minutes,
            seconds;
        function timer() {
            // get the number of seconds that have elapsed since 
            // startTimer() was called
            diff = duration - (((Date.now() - start) / 1000) | 0);
    
            // does the same job as parseInt truncates the float
            minutes = (diff / 60) | 0;
            seconds = (diff % 60) | 0;
    
            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;
    
            display.textContent = minutes + ":" + seconds; 
    
            if (diff <= 0) {
                // add one second so that the count down starts at the full duration
                // example 05:00 not 04:59
                start = Date.now() + 1000;
            }
        };
        // we don't want to wait a full second before the timer starts
        timer();
        setInterval(timer, 1000);
    }
    
    window.onload = function () {
        var fiveMinutes = 60 * 5,
            display = document.querySelector('#time');
        startTimer(fiveMinutes, display);
    };
    <body>
        <div>Registration closes in <span id="time"></span> minutes!</div>
    </body>

    Now that we have made a few pretty simple timers we can start to think about re-usability and separating concerns. We can do this by asking "what should a count down timer do?"

    So with these things in mind lets write a better (but still very simple) CountDownTimer

    function CountDownTimer(duration, granularity) {
      this.duration = duration;
      this.granularity = granularity || 1000;
      this.tickFtns = [];
      this.running = false;
    }
    
    CountDownTimer.prototype.start = function() {
      if (this.running) {
        return;
      }
      this.running = true;
      var start = Date.now(),
          that = this,
          diff, obj;
    
      (function timer() {
        diff = that.duration - (((Date.now() - start) / 1000) | 0);
            
        if (diff > 0) {
          setTimeout(timer, that.granularity);
        } else {
          diff = 0;
          that.running = false;
        }
    
        obj = CountDownTimer.parse(diff);
        that.tickFtns.forEach(function(ftn) {
          ftn.call(this, obj.minutes, obj.seconds);
        }, that);
      }());
    };
    
    CountDownTimer.prototype.onTick = function(ftn) {
      if (typeof ftn === 'function') {
        this.tickFtns.push(ftn);
      }
      return this;
    };
    
    CountDownTimer.prototype.expired = function() {
      return !this.running;
    };
    
    CountDownTimer.parse = function(seconds) {
      return {
        'minutes': (seconds / 60) | 0,
        'seconds': (seconds % 60) | 0
      };
    };
    

    So why is this implementation better than the others? Here are some examples of what you can do with it. Note that all but the first example can't be achieved by the startTimer functions.

    An example that displays the time in XX:XX format and restarts after reaching 00:00

    An example that displays the time in two different formats

    An example that has two different timers and only one restarts

    An example that starts the count down timer when a button is pressed