Keeping Ajax timer synchronised

2019-09-02 11:16发布

I have the following jQuery function that I'm using to display a timer on a page:

function update() {
  $.ajax({
    type: 'POST',
    url: 'check_time.php',
    data: 'checktime=true',
    timeout: 0,
    success: function(data) {
        $(".time_remaining").html(data);
        window.setTimeout(update, 1000);
        var time = data;
        if(time<=0)
        {
            $(".time_remaining").html("Reloading the page now.");
            refresh();
        }
        else
        {
            $(".time_remaining").html("There are "+data+" seconds left." );
        }
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      $("#notice_div").html('Error contacting server. Retrying in 60 seconds.');
      window.setTimeout(update, 60000);
    }
});
};

As you can see, it's actually running a script that calculates how much time is remaining until a refresh is called (with the refresh() function). I feel this is a bit intensive because it's calling every second, but I feel it's important at the same time to have synchrony in the Ajax because if the refresh() function is called too early the page stops running in sync.

How can I make it that the timer is still always decreasing in time, but only synchronises with the server every 30 seconds or so?

Precision is really important for this application.

2条回答
够拽才男人
2楼-- · 2019-09-02 11:27

Something like this:

function update(secs) {
  if (secs % 30 == 10) {
    $.ajax({
     ...
       window.setTimeout("update(" + (data - 1) + ");", 1000);
     ...
    });
  } else {
    $(".time_remaining").html("There are "+secs+" seconds left." );
    window.setTimeout("update(" + (secs - 1) + ");", 1000);
  }
}

I've tested that secs modulo 30 is 10 because that gives you an accurate last 10 secs.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-09-02 11:30

Use a variable remainingTime to store the remaining time:

var remainingTime;

Update with ajax:

function update() {
    $.ajax(..., success: function(data) {
        remainingTime = parseInt(data, 10);
    });
}

Continuously update:

setInterval(update, 30 * 1000);

Countdown:

function countdown() {
    if(remainingTime-- < 0) {
        $(".time_remaining").text("Reloading the page now.");
        refresh();
    } else {
        $(".time_remaining").text("There are " + remainingTime + " seconds left." );
    }
}

Continuously countdown:

setInterval(countdown, 1000);

NOTE: It might be the case that you want to setTimeout inside the success handler, as you already did, and a longer timeout in the error handler. But this should do the trick for decoupling the updating from the display.

You definitely should use setInterval for the countdown though, because setInterval tries to trigger with that exact interval, whereas setTimeout will cause drift, that is, if it takes 10ms to update the DOM, the next call will only occur after 1010ms, and so on. With setInterval, this is not the case because the browser will do its best to actually trigger that function every 1000 ms.

查看更多
登录 后发表回答