Mingsho Nembang Mingsho Nembang - 7 months ago 10
Javascript Question

jQuery timer pauses when browser is out of focus

I'm facing this problem in Chrome and Mozilla, while IE works fine. The timer pauses when I minimize the browser or open a new tab and work on that tab for a while, but then resumes again if the web application is in focus again. I know this by the difference in the time, e.g. after about a minute or so only a second or so will have elapsed when I return to the web application. I don't know what is causing this issue.

Here is the jQuery snippet that I used, the timer can be downloaded from here http://code.google.com/p/jquery-timer/

var countdownTimer, countdownCurrent;
$(document).ready(function () {
countdownCurrent = $('#ctl00_MainContent_example2submit').val() * 100;
countdownTimer = $.timer(function () {
var min = parseInt(countdownCurrent / 6000);
var sec = parseInt(countdownCurrent / 100) - (min * 60);
var micro = pad(countdownCurrent - (sec * 100) - (min * 6000), 2);
var output = "00"; if (min > 0) { output = pad(min, 2); }
$('.countdowntime').html(output + ":" + pad(sec, 2) + ":" + micro);
if (countdownCurrent == 0) {
$('#ctl00_MainContent_btnNext').click();

} else {
countdownCurrent -= 7;
if (countdownCurrent < 0) { countdownCurrent = 0; }
}
}, 70, true);


$('#example2submit').bind('keyup', function (e) { if (e.keyCode == 13) { countdownReset(); } });

});

function CheckIfOptionSelected() {

var vFlag = true;
var radioButton1 = document.forms[0].elements['ctl00_MainContent_rdBtnListOptions_0'];
var radioButton2 = document.forms[0].elements['ctl00_MainContent_rdBtnListOptions_1'];
var radioButton3 = document.forms[0].elements['ctl00_MainContent_rdBtnListOptions_2'];
var radioButton4 = document.forms[0].elements['ctl00_MainContent_rdBtnListOptions_3'];

if (radioButton1.checked == false && radioButton2.checked == false && radioButton3.checked == false && radioButton4.checked == false && countdownCurrent > 0) {
vFlag = false;
}

else {
countdownReset();
vFlag = true;
}
return vFlag;
}

function countdownReset() {
var newCount = parseInt($('#ctl00_MainContent_example2submit').val()) * 100;
if (newCount > 0) { countdownCurrent = newCount; }
countdownTimer.stop().once();
}

// Padding function
function pad(number, length) {
var str = '' + number;
while (str.length < length) { str = '0' + str; }
return str;
}

Answer

I took a look at that jQuery timer plugin, and I don't like the code much. It seems unnecessarily complicated for a simple task. Code like this does not inspire confidence:

if(typeof func == 'object') {
    var paramList = ['autostart', 'time'];
    for(var arg in paramList) {if(func[paramList[arg]] != undefined) {eval(paramList[arg] + " = func[paramList[arg]]");}};
    func = func.action;
}

Reformatted with some much-needed line breaks and comments added:

if(typeof func == 'object') {
    var paramList = ['autostart', 'time'];
    // Never use for..in to iterate over an array
    for(var arg in paramList) {
        if(func[paramList[arg]] != undefined) {
            // What does this eval code do and why?
            eval(paramList[arg] + " = func[paramList[arg]]");
        }
    };
    func = func.action;
}

If you need a timer that works, why not take a simpler approach and use the browser's setInterval() or setTimeout() directly? And if you need to know how much time has elapsed, use +new Date to get the current time in milliseconds and subtract as needed.

Here's a test page that displays the number of seconds since the page was loaded. It's pure native HTML and JavaScript code and I think it should work in every browser. In particular, it works as expected when IE is minimized. You could use this as a starting point for a simple and reliable solution:

<!DOCTYPE html>

<html>
<head>
    <title>Time Test</title>
</head>
<body>

    <code>
        This page has been open for
        <span id="timeOpen">0</span>
        seconds
    </code>

    <script>
        var timeStart = +new Date;
        setInterval( function() {
            var timeNow = +new Date;
            var secondsOpen = ( timeNow - timeStart ) / 1000;
            document.getElementById('timeOpen').innerHTML =
                Math.floor( secondsOpen );
        }, 250 );
    </script>

</body>
</html>

And here's the code in a fiddle.