首页 > 解决方案 > 多个ajax倒计时的建议(每秒调用)

问题描述

我正在创建一个具有 100 个倒计时的系统。每个计时器每秒进行一次 ajax 调用,以获取数据库中的 endTime 并更新倒计时时间。我需要每秒调用一次,因为 endTime 可以改变。该系统目前正在运行,但速度非常慢,我很好奇是否有比每秒调用 100 次 ajax 调用更好的方法。

var countDownDate;
    var is_locked;
    var interval = 1000;

    function update_timer() {
      $.ajax({
        type: 'POST',
        url: '<?php echo base_url('/Timer/getTimer');?>',
        data: {
          id: <?php echo $lane->id; ?>,
        },
        async: false,
        dataType: 'json',
        success: function (response) {
          var image_url = null;
          $.each(response, function(k, v) {
            if (k == 'end_time') {
              countDownDate = new Date(v).getTime();
            }
            if (k == 'is_locked') {
              is_locked = v;
              if (is_locked == 1) {
                $('.myButton').prop('disabled', true);
              } else {
                $('.myButton').prop('disabled', false);
              }
            }
          })
          // Get today's date and time
          var now = new Date().getTime();

          // Find the distance between now and the count down date
          var distance = countDownDate - now;
          // Time calculations for days, hours, minutes and seconds
          var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
          var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
          var seconds = Math.floor((distance % (1000 * 60)) / 1000);

          // Display the result in the element with id="demo"
          document.getElementById("demo").innerHTML =  hours + "h "
            + minutes + "m " + seconds + "s ";

          // If the count down is finished, write some text
          if (distance < 0) {
            //clearInterval(x);
            document.getElementById("demo").innerHTML = "EXPIRED";
          }
        },
        complete: function (data) {
          // Schedule the next
          setTimeout(update_timer, interval);
        }
      });
    }
    update_timer;
    setTimeout(update_timer, interval);

标签: javascriptphpajax

解决方案


正如@CertainPerformance 所评论的那样,Websockets 是针对这种情况的干净而漂亮的解决方案

@Thum Choon Tat 建议的这种解决方法怎么样

与其让 100 个计时器中的每一个每 1 秒发出一次请求以获取他自己的endTime请求(每秒 100 个请求),不如每秒仅发出 1 个请求并获得所有计时器endtimes

这是我的计划

  • 我们将使用 localStorage 在所有选项卡之间共享数据。并将这些项目保存在其中:

    1. lastRequeted任何 HTML 页面最后一次发出请求。
    2. requesterId负责触发 Ajax 请求的页面的 ID
    3. timerId1, timerId2, timerId3, .... 将为endTimes每个计时器保留
  • 任何具有 100 个计时器中的一个或多个计时器的页面都可以请求endTimes所有计时器中的一个,并将lastRequeted值设置为现在,并将其设置requesterId为 Id

  • 我们每秒在客户端运行一个间隔来检查lastRequeted,如果它太旧“像 4 秒前”,它会执行请求,如果它是新的,那么它会从timerIdX项目中获取它需要的数据。
  • 只有一个 HTML 页面会自行注册,因为requesterId除非数据太旧,否则其他 HTMl 页面不会发出请求

这是您将在任何具有计时器的 HTML 上使用的 JS 代码

var requesterId = Math.random(); // random Id for this page

setInterval(function (){
    var ts = Math.floor(Date.now() / 1000);
    var lastRequested = localStorage.getItem('lastRequested');
    var currentRequester = localStorage.getItem('requesterId');

    if (requesterId == currentRequester ||  (ts - lastRequested > 4)){
        // if I'm the current requester or the last requested time is older than 4 seconds, I will do the request
        localStorage.settItem('requesterId', requesterId);
        $.ajax({
        type: 'POST',
        url: '/Timer/getAllTimers',
        dataType: 'json',
        success: function(data){
             localStorage.setItem('lastRequested', Math.floor(Date.now() / 1000));
             for (var i =0; i < data.length; i++){
                 var timerId = data[i].timerId;
                 var timerEndTime = data[i].timerEndTime;
                 localStorage.setItem(timerId, timerEndTime);
             }
             updateTimersEndTimes();
        }
    } else {
        // the data is updated I will get the timer endTime
        updateTimersEndTimes();

    }
}, 1000);

/**
 * update timers endTimes from the localStorage
*/
function updateTimersEndTimes()
{
     /*
      // pseudo code
      $("Div#timersOnPage .timer").each(function(){
          var timerId = $(this).data("timerId");
          var timerEndtime = LocalStorage.getItem(timerId);
          $(this).data('timerEndTime', timerEndtime);
     });

     */
}

在服务器上,您将发送所有计时器的 endTime

/定时器/getAllTimers

<?php
//buid the array from your database
$timersArray = [];
for ($i = 0; $i < 100; $i++){
    $timer = new stdClass();
    $timer->timerId = $i;
    $timer->timerEndTime = "2019-08-23 05:02:23";//changes for every timer
    $timersArray[] = $timer;
}

header('Content-Type: application/json');
echo json_encode($timersArray);
exit;

现在每个具有计时器的 HTML 都不会触发请求,但是如果计时器数据更新,它将每秒检查一次,然后它将使用它。


推荐阅读