How to pause and resume a javascript timer

user2303981 picture user2303981 · Apr 21, 2013 · Viewed 18.1k times · Source

I have this timer which works fine, but i need to be able to pause and resume it after that. i would appreciate it if someone could help me.

<html>
<head>
<script>
function startTimer(m,s)
    {
        document.getElementById('timer').innerHTML= m+":"+s;
        if (s==0)
            {
               if (m == 0)
                {
                    return;
                }
                else if (m != 0)
                {
                    m = m-1;
                    s = 60;
                }
        }
    s = s-1;
    t=setTimeout(function(){startTimer(m,s)},1000);
}


</script>
</head>

<body>
<button onClick = "startTimer(5,0)">Start</button>

<p id = "timer">00:00</p>
</body>
</html>

Answer

Niet the Dark Absol picture Niet the Dark Absol · Apr 21, 2013

I simply can't stand to see setTimeout(...,1000) and expecting it to be exactly 1,000 milliseconds. Newsflash: it's not. In fact, depending on your system it could be anywhere between 992 and 1008, and that difference will add up.

I'm going to show you a pausable timer with delta timing to ensure accuracy. The only way for this to not be accurate is if you change your computer's clock in the middle of it.

function startTimer(seconds, container, oncomplete) {
    var startTime, timer, obj, ms = seconds*1000,
        display = document.getElementById(container);
    obj = {};
    obj.resume = function() {
        startTime = new Date().getTime();
        timer = setInterval(obj.step,250); // adjust this number to affect granularity
                            // lower numbers are more accurate, but more CPU-expensive
    };
    obj.pause = function() {
        ms = obj.step();
        clearInterval(timer);
    };
    obj.step = function() {
        var now = Math.max(0,ms-(new Date().getTime()-startTime)),
            m = Math.floor(now/60000), s = Math.floor(now/1000)%60;
        s = (s < 10 ? "0" : "")+s;
        display.innerHTML = m+":"+s;
        if( now == 0) {
            clearInterval(timer);
            obj.resume = function() {};
            if( oncomplete) oncomplete();
        }
        return now;
    };
    obj.resume();
    return obj;
}

And use this to start/pause/resume:

// start:
var timer = startTimer(5*60, "timer", function() {alert("Done!");});
// pause:
timer.pause();
// resume:
timer.resume();