Search code examples
javascriptjquerytimercountdown

Gmail-like countdown timer not working


I've been trying to recreate a countdown timer similar to the one gmail uses that when you get disconnected from internet. The ajax request fails then it begin a short countdown then makes another ajax request and if it fails again then begin a longer countdown and so forth. Once a determined countdown value is reached (lets say 1 minute), the countdown is maintained at 1 minute until the internet connection is recovered or the servers comes back.

I don't want to use a plugin because this code will be embedded in a micro-controller that has limited space and also prefer not to place it as external file for practical reasons, even though jQuery library will already be external.

Everything should trigger onload, and continue automatically (i.e. no control inputs will be used).

So far I've developed code that does what I want if the ajax request succeeds or fails immediately but if there is a latency on the ajax request status (as for example having the server down) the browser won't produce an immediate result and my code fails.

I know what I stated above because I actually took the server down and was been help by firebug on Mozilla Firefox to see that the ajax result (success or failure) wasn't triggered immediately but keep waiting for several seconds.

Help please!

html code:

<div id='tempFail' ></div>

jQuery code:

$(document).ready(function()
{ 
    //do when DOM ready - http://api.jquery.com/ready/

    var timerSpeed = [1000, 5000, 10000, 20000, 30000, 60000];

    // current time in ms since 1/1/1970, plus the initial reload interval
    var end = (new Date).getTime() + timerSpeed[1];  
    var n=0;
    var m=0;

    setInterval(function() 
    {
        var now = (new Date).getTime();
        // Current time left to re-load in seconds, sometimes it goes to negative values, see below 

        var secLeft = Math.floor(( end - now ) / 1000);

        // if secLeft is negative multiply by zero...equal to secLeft=0, this will produce an error of one second approximately      
        var timeToload = (secLeft < 0) ? secLeft * 0 : secLeft;  

        if (n!=0) 
        { 
            //check for failed or delayed request\n\       

            $('#tempFail').html('Failed or delayed response. Will auto load in: '+timeToload+ ' seconds!'); 
        }

        if( (secLeft)<=0)// if reload time is reached do
        {                      

            if (m==0)//used to prevent multiple continue reloads when ajax request status is not yet defined
            {                            

                m=1;    

                $.getScript('script_vars.js').done(function (data) 
                {         
                    //if request succeeded
                    m=0;
                    n = 0;
                    end = (new Date).getTime() + timerSpeed[1];  
                    // Time to load after the initial interval set above
                    $('#tempFail').html(''); 

                //other code on success  here         
                })
                .fail(function() 
                {      
                    //if request failed
                    m=0;
                    n ++;
                    if(n==6) n=5;

                   switch(n){         //timer delay for failed request\n\


                     case 1:

                       end = (new Date).getTime() + timerSpeed[1];
                       break;

                     case 2:

                        end = (new Date).getTime() + timerSpeed[2];
                       break;

                     case 3:

                        end = (new Date).getTime() + timerSpeed[3];
                       break;

                     case 4:

                       end = (new Date).getTime() + timerSpeed[4];
                       break;

                     case 5:

                        end = (new Date).getTime() + timerSpeed[5];
                       break;  
                  } 


               });      

         }
        }                


        }, 1000);

     });

Solution

  • You asked for an example so I've written the following, you may want to wrap the contents of the function within another function so you can repeat it/don't have to worry about namespaces/etc. Didn't test so don't expect bug free!

    Using window.setTimeout for every action, separated each stage into it's own function so code paths can more easily be followed.

    $(document).ready(function () { // http://api.jquery.com/ready/
        var $tempFail = $('#tempFail'),
            delay = [1000, 5000, 10000, 20000, 30000, 60000],
            delay_index = 0,
            delay_ends = 0,
            inform_user_ref = null,
            inform_user = function inform_user() {
                var now = (new Date).getTime(),
                    delta; // for difference, calculate later
                if (delay_ends > now) { // if we're waiting for a retry
                    delta = Math.floor((delay_ends - now ) / 1000); // calculate time to wait
                    $tempFail.html('Failed or delayed response. Will auto load in: '+delta+ ' seconds!'); // let people know
                    window.setTimeout(inform_user, 200); // loop countdown timer
                    // can fast refresh this as it's just a countdown
                }
            },
            get_success = function () {
                $tempFail.html('');
                // .. code on success
            },
            get_fail = function () {
                delay_index < 5 && ++delay_index; // increment delay_index
                get_initialise(); // retry
                window.clearTimeout(inform_user_ref); // remove any old countdown timer
                inform_user_ref = inform_user(); // and display new countdown
            },
            get_try = function () {
                $.getScript('script_vars.js')
                    .done(get_success)
                    .fail(get_fail);
            },
            get_initialise = function () {
                delay_ends = (new Date).getTime() + delay[delay_index];
                window.setTimeout(get_try, delay[delay_index]); // retry
            };
        get_initialise(); // initial
    });