【问题标题】:JavaScript setTimeout and changes to system time cause problemsJavaScript setTimeout 和更改系统时间会导致问题
【发布时间】:2023-03-06 18:45:01
【问题描述】:

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

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

我的 JavaScript 网页使用setTimeout 函数每 5 秒自动刷新一次页面,如果出现夏令时,页面信息将冻结一个小时。有解决办法吗?

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

【问题讨论】:

  • 发生夏令时更改时,实际上是时区偏移更改,而不是对 UTC 的更改。如果 DST 由系统自动处理,您执行的测试不会模拟实际发生的情况。 Leap seconds 可能仍然会造成问题,但是,如果计算机的时钟与实际时间相差甚远(因此它不会逐渐改变时间),自动时间同步也会产生问题。
  • 我刚刚在 Windows 7 上的 IE7、IE8、IE9、Firefox 和 Chrome 中对此进行了测试,但没有看到您描述的行为。也许这是特定于操作系统的?
  • @idealmachine,有没有一种简单的方法来测试夏令时?
  • @gilly3,我可以在 Ubuntu 10.10 上使用最新的 Google Chrome 和 Firefox 3.6 随意重现这个问题
  • 如前所述,DST 正在改变时区偏移量。为了测试它,你只需要改变你的时区。

标签: javascript settimeout system-clock


【解决方案1】:

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

更好的办法是使用 Web 套接字并将 Comet 作为后备。这很容易通过Fayesocket.io 实现。

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

【讨论】:

    【解决方案2】:

    使用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 将事件触发移动到服务器。不这样做的原因有很多,最重要的是你会集中事件并使它们成为服务器的负担,但它可以被认为是最后的手段。

    【讨论】:

    • 不幸的是,这并没有解决这个问题。同样的事情也会发生。
    • 不幸的是 setInterval 明显更差。
    • 这很奇怪 - 你在什么操作系统上?我无法在任何浏览器中使用 win7 64 位上的 setInterval 重现此问题。
    【解决方案3】:

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

    一些背景:

    • IE 和 Opera 可以正确处理系统时间更改(对setTimeout()setInterval() 没有副作用)。
    • FF

    我的解决方案:使用来自用户交互的一些事件(即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;
    }
    

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

    【讨论】:

      【解决方案4】:

      我发现使用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);
        });
      }
      

      【讨论】:

        【解决方案5】:

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

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

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

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

        【讨论】:

        • 我编辑了我的问题以添加我正在使用 Ajax 更新页面,并且无法刷新它。
        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-27
          • 1970-01-01
          相关资源
          最近更新 更多