22

我注意到如果我setTimeout在未来设置为 1 分钟,然后将我的系统时间更改为过去的 5 分钟,该setTimeout功能将在 6 分钟后触发。

我这样做是因为我想看看在夏令时更改系统时钟期间会发生什么。

我的 JavaScript 网页使用了一个setTimeout功能,每 5 秒自动刷新一次页面,如果要进行夏令时,那么页面信息将冻结一个小时。有解决方法吗?

编辑:我正在使用 Ajax 更新页面,我不想刷新整个页面。

4

6 回答 6

4

使用setInterval代替,setTimeout你的问题应该得到解决:)

更新:

如果你真的不能使用 setTimeout 或 setInterval,你可以尝试隐藏iframe一个加载一个简单的 HTML 页面,看起来像这样:

<html>
    <head>
        <meta http-equiv="refresh" content="300"/>
        <script>
            document.domain='same as parent page';
            top.ajax_function_you_wish_to_trigger();
        </script>
    </head>
    <body>
    </body>
</html>

如果你幸运的话,元刷新不会给你带来同样的问题。

另一种解决方案是通过server push将事件触发移动到服务器。不这样做的原因有很多,尤其是您要集中事件并使它们成为服务器的负担,但它可以被认为是最后的手段。

于 2011-02-02T23:05:03.680 回答
4

我要做的是将每 5 秒打开一个新的 Ajax 请求更改为使用Comet(长轮询)。这是一个更好的选择,因为每次需要新结果时,服务器都会将新结果推送到浏览器,这可以是服务器端每 5 秒一次或每次有新信息可用时。

更好的是使用网络套接字并将 Comet 作为后备。这很容易用Fayesocket.io实现。

还有其他选择,例如 CometD 或 Ape。

于 2011-02-13T20:56:52.553 回答
2

我最近也遇到了这个问题。就我而言,时间变化可能会导致严重的经济损失,所以我必须认真对待。

一些背景:

  • setTimeout()IE 和 Opera 可以正确处理系统时间更改(对,没有副作用setInterval())。
  • FF < 4.0 并且所有基于 Webkit 的浏览器都无法处理过去的时间变化(正如您所描述的那样)。注意:Chrome 中的计时器仅在大约 2-60 秒后才会停止。

我的解决方案:使用来自用户交互的一些事件(即mousemovemouseover等)来触发时间更改检查。

Clock.prototype.checkLocalTime = function(){
  var diff = Date.now()- this.lastTimestamp;
  if ( diff < 0 || diff > 20000) { // if time shifted back or more than 20s to the future
    console.warn('System time changed! By ' + diff + 'ms' );
    this.restartTimer();
    this.getServerTime();
  }
  this.lastTimestamp = time;
}

如您所见,我重新启动计时器并另外与服务器同步时间。

于 2011-02-20T20:14:16.457 回答
1

我发现使用window.performance给了我更准确的结果,并在系统时间发生变化时保持一致。

我用它作为在 setInterval 刻度内获取当前时间的一种方法,这样倒计时计时器就不会受到系统时间更改的影响。我根据给定时间的滴答数来计算它,以尝试通过更改系统时钟来防止在计时器上作弊(获得更多时间)

getCurrentTime = () => {
  return window.performance ?
    performance.timing.navigationStart + performance.now() : Date.now();
}

tick() {
  let now = this.getCurrentTime();

  if (this.calibrateTime) { //calibrate with a given server time
    now -= this.timeCalibration;
  }

  const elapsedSeconds = (now - this.startedAt) / 1000;

  if (elapsedSeconds > this.props.timeLimit + this.props.submitBuffer) {
    clearInterval(this.interval);
    this.props.onTimeUp();
  }

  let secondsRemaining = this.props.timeLimit - Math.floor(elapsedSeconds);
  if (secondsRemaining < 0) secondsRemaining = 0;

}

startTimer() {
  if (!this.startedAt) {
    this.startedAt = Date.now();
  }

  this.setState({ started: true }, () => {
    this.interval = setInterval(this.tick.bind(this), 500);
  });
}
于 2018-03-23T14:44:00.183 回答
0

您可以使用元标记刷新来执行此操作。此代码将每 5 秒刷新一次页面:

<meta http-equiv="refresh" content="5"> 

至于javascript问题,它可能只是浏览器处理setTimeout的方式。它告诉浏览器在设定的时间执行代码,然后当时钟改变时,代码仍然在时钟改变之前的时间执行?只是一个猜测,但我下次使用 setTimeout 时必须记住这一点。

编辑:好的,这不适用于 ajax 再次编辑:这是一个非常好的问题。我确信 setTimeout 的功能正如我上面所说的那样,但是哇,这是一个脑筋急转弯。

于 2011-02-02T22:56:35.590 回答
0

您可以捏造并进行if (Date in range foo)检查。基本上检查当前时间戳是否在夏令时的 5 秒内,然后立即刷新页面,而不是使用setTimeout.

这样,用户在已知时间变化附近会感到轻微的烦恼,但页面不会冻结一个小时。

于 2011-02-13T20:58:57.043 回答