倒数计时器问题

Count Down Timer Issue

我正在 PHP 创建一个定时测试产品。我在正确安排考试时间方面遇到了问题。当考试开始时,只要我在同一个屏幕上,计时器就会正常工作。但是,当我在测试进行时(比如 10 分钟)打开其他屏幕,并在一段时间后返回测试时,计时器显示错误的时间,并且显示前 10 分钟的测试时间似乎只有 2 分钟。

只是想知道为什么当我在测试进行时移出屏幕并在一段时间后返回时测试计时器的这种不稳定行为。

谁能帮我解决这个问题?

PHP 代码

<?php
/*Timer Code*/
        $dateFormat = "d F Y -- g:i a";
        $targetDate = time() + (240*60);//Change the 240 to however many minutes you want to countdown
        $actualDate = time();
        $secondsDiff = $targetDate - $actualDate;
        $remainingDay     = floor($secondsDiff/60/60/24);
        $remainingHour    = floor(($secondsDiff-($remainingDay*60*60*24))/60/60);
        $remainingMinutes = floor(($secondsDiff-($remainingDay*60*60*24)-($remainingHour*60*60))/60);
        $remainingSeconds = floor(($secondsDiff-($remainingDay*60*60*24)-($remainingHour*60*60))-($remainingMinutes*60));
        $actualDateDisplay = date($dateFormat,$actualDate);
        $targetDateDisplay = date($dateFormat,$targetDate);
?>

JavaScript

/*Timer Code*/
  var days = <?php echo $remainingDay; ?>  
  var hours = <?php echo $remainingHour; ?>  
  var minutes = <?php echo $remainingMinutes; ?>  
  var seconds = <?php echo $remainingSeconds; ?> 

function setCountDown ()
{
  seconds--;
  if (seconds < 0){
      minutes--;
      seconds = 59
  }
  if (minutes < 0){
      hours--;
      minutes = 59
  }
  if (hours < 0){
      days--;
      hours = 23
  }
  document.getElementById("remain").innerHTML = "Time "+hours+" H : "+minutes+" M : "+seconds+" S";
  SD=window.setTimeout( "setCountDown()", 1000 );
  if (hours == '0' && minutes == '00' && seconds == '00') 
  { 
      seconds = "00"; window.clearTimeout(SD);
      timeStatus = 1;
      var response = window.alert("Time is up. Press OK to continue."); // change timeout message as required         
  } } // here is the end of setCountDown

这适用于我列出的更改:

PHP:

<?php
/*Timer Code*/
        $dateFormat = "d F Y -- g:i a";
        $targetDate = time() + (240*60);//Change the 240 to however many minutes you want to countdown
        $actualDate = time();
        $secondsDiff = $targetDate - $actualDate;
        $remainingDay     = floor($secondsDiff/60/60/24);
        $remainingHour    = floor(($secondsDiff-($remainingDay*60*60*24))/60/60);
        $remainingMinutes = floor(($secondsDiff-($remainingDay*60*60*24)-($remainingHour*60*60))/60);
        $remainingSeconds = floor(($secondsDiff-($remainingDay*60*60*24)-($remainingHour*60*60))-($remainingMinutes*60));
        $actualDateDisplay = date($dateFormat,$actualDate);
        $targetDateDisplay = date($dateFormat,$targetDate);
?>
  • PHP开场应该是

JavaScript:

/*Timer Code*/
  var days = 0;
  var hours = 4;
  var minutes = 0;
  var seconds = 0;

  setCountDown();

function setCountDown ()
{
  seconds--;
  if (seconds < 0){
      minutes--;
      seconds = 59
  }
  if (minutes < 0){
      hours--;
      minutes = 59
  }
  if (hours < 0){
      days--;
      hours = 23
  }
  if (hours == '0' && minutes == '00' && seconds == '00') 
  { 
      seconds = "00"; 
      window.clearTimeout(SD);
      timeStatus = 1;
      var response = window.alert("Time is up. Press OK to continue."); // change timeout message as required         
  } 
  console.log(days+'/'+hours+'/'+minutes+'/'+seconds);
  SD=setTimeout(setCountDown, 1000);
}
  • setCountDown 缺少右括号
  • setTimeout 应该只用函数名调用。在名称将返回值传递给 setTimeout 之后用 () 调用它,而不是函数本身。 (最后一点与您的问题无关,因为您在引号中调用了函数)
  • 函数的重新调用应该在你检查你是否在 0 之后。

为了更准确的计时器系统,请考虑使用来自服务器和用户计算机的时间戳,而不是可以操纵的变量。然后就可以不断的从用户电脑中拉取当前时间,看看已经过去了多少时间。

当 运行 不在前台时,

JavaScript 不会总是处理计时器滴答,所以这就是你变慢的原因。

如果你这样做会更可靠:

  • 在 JS 中使用目标期限,每次处理计时器事件时将其转换为剩余时间。这样,它将始终与实际截止日期相关。
  • 不时从服务器刷新截止日期信息(不是每秒,但可能每 5 分钟)。这意味着您必须在服务器端使用某种持久性,例如具有截止日期的会话范围变量,您可以通过它 return 剩余的秒数。
  • 在服务器端验证没有在截止日期之后提交答案(如果有人篡改了客户端)。同样,您需要一些会话范围用法来实现它。

我不会提供第二个或第三个想法的代码,但这里是适应第一个想法的代码(这可能足以满足您的目的?):

/*Timer Code*/
var totalSeconds = 240*60; //<?php echo 240*60; ?>  
var deadlineMillis = Date.now() + totalSeconds * 1000;

function setCountDown () {
    var secondsRemaining = Math.max(0, Math.round((deadlineMillis - Date.now()) / 1000)),
        minutes = Math.floor(secondsRemaining / 60),
        hours = Math.floor(minutes / 60),
        days = Math.floor(hours / 24);
    hours = hours % 24;
    minutes = ('0' + (minutes % 60)).substr(-2);
    seconds = ('0' + (secondsRemaining % 60)).substr(-2);
    document.getElementById("remain").textContent = 
        "Time "+hours+" H : "+minutes+" M : "+seconds+" S";
    if (secondsRemaining === 0) { 
        timeStatus = 1;
        alert("Time is up. Press OK to continue."); // change timeout message as required
        return;
    }
    setTimeout(setCountDown, 1000);
}

setCountDown();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="remain"></div>

用 PHP 生成的值替换 240*60

大多数现代浏览器有意降低非活动状态的优先级 tabs/windows。因此计时器将减慢。所以你面对的不是古怪的行为。它是为了提高浏览器性能而设计的。

https://developers.google.com/web/updates/2017/03/background_tabs#budget-based_background_timer_throttling

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Timeouts_in_inactive_tabs_throttled_to_>1000 毫秒

解决方案:使用 web worker