5

我正在开发一个对时间非常敏感的 Web 应用程序。给我的业务规则之一是应用程序的行为必须始终取决于 Web 服务器上的时间,而不管客户端时钟上的时间。为了让用户清楚这一点,我被要求在 Web 应用程序中显示服务器的时间。

为此,我编写了以下 Javascript 代码:

clock = (function () {
var hours, minutes, seconds;

function setupClock(updateDisplayCallback) {
    getTimeAsync(getTimeCallback);

    function getTimeCallback(p_hours, p_minutes, p_seconds) {
        hours = p_hours;
        minutes = p_minutes;
        seconds = p_seconds;
        setInterval(incrementSecondsAndDisplay, 1000);
    }

    function incrementSecondsAndDisplay() {
        seconds++;
        if (seconds === 60) {
            seconds = 0;
            minutes++;
            if (minutes === 60) {
                minutes = 0;
                hours++;
                if (hours === 24) {
                    hours = 0;
                }
            }
        }
        updateDisplayCallback(hours, minutes, seconds);
    }
}

// a function that makes an AJAX call and invokes callback, passing hours, minutes, and seconds.
function getTimeAsync(callback) {
    $.ajax({
        type: "POST",
        url: "Default.aspx/GetLocalTime",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            var date, serverHours, serverMinutes, serverSeconds;
            date = GetDateFromResponse(response);
            serverHours = date.getHours();
            serverMinutes = date.getMinutes();
            serverSeconds = date.getSeconds();
            callback(serverHours, serverMinutes, serverSeconds);
        }     
    })
}

return {
    setup: setupClock
};
})();

传入的函数updateDisplayCallback是一个在网页上显示日期的简单函数。

基本思想是Javascript进行异步调用以查找服务器的时间,将其存储在客户端上,然后每秒更新一次。

起初,这似乎可行,但随着时间的推移,显示的时间每分钟落后几秒钟。我让它通宵运行,当我第二天早上进来时,它已经关闭了一个多小时!这是完全不可接受的,因为 Web 应用程序可能一次保持打开数天。

如何修改此代码,以便网络浏览器连续准确地显示服务器的时间?

4

3 回答 3

6

Javascript 的 setInterval 不够准确,无法让您保持这样的时间。

我的解决方案是:

  1. 以毫秒为单位定期获取服务器的时间(不需要非常频繁,因为两个时钟几乎不会偏离那么多)
  2. 以毫秒为单位获取客户端时间
  3. 计算服务器和客户端之间的时钟偏差(client-server)
  4. 通过获取客户端时间并添加时钟偏差来定期更新时钟的显示

编辑:为了更准确,您可以测量服务器请求的往返时间,将其除以 2 并将延迟计入时钟偏差。假设往返行程的持续时间是对称的,这将给出更准确的计算。

于 2013-03-29T14:26:19.863 回答
2

setInterval不是安排时间关键事件的可靠方法。1000ms根据当前 JavaScript 的繁忙程度,运行回调可能需要更少或更多时间。

更好的方法是采取更短的间隔并用于new Date().getTime()检查是否已经过了一秒。

浏览器允许的最小时间间隔一样高10

于 2013-03-29T14:21:55.393 回答
0

感谢您的回答。只要它们包含有用的信息,我对这两个答案都投了赞成票。但是,我没有使用任何一个答案中规定的确切答案。

我最终决定的有点不同。

我在我的个人网页上写下了我学到的东西。

首先,我现在明白了,setInterval(..., 1000)长时间每秒做一次事情还不够好。但是,以更短的间隔“轮询”时间以寻找第二个更改对我来说似乎效率很低。

我认为跟踪服务器时间和客户端时间之间的“偏移量”确实有意义。

我的最终解决方案是执行以下操作:

(1) 对服务器进行 AJAX 调用以获取时间。该函数还检查客户端时间并计算服务器时间和客户端时间之间的差异,以毫秒为单位。由于网络延迟和其他因素,此初始提取可能会延迟几秒钟。就我的目的而言,这没关系。

(2) 执行一个tick函数。每次tick执行时,它都会检查自上次tick执行以来已经过去了多长时间。它将使用此时间来计算要传递给的参数,setTimeout以便时间显示大约每秒更新一次。

(3) 每次tick函数计算要显示的时间时,它都会占用客户端时间并加上在步骤 (1) 中计算的差值。这样,我不依赖于客户来正确设置时间,但我确实依赖于客户来准确测量经过的时间。就我的目的而言,这没关系。最重要的是,无论多么setTimeout不准确或被其他进程(例如模态对话框)打断,显示的时间都应该始终准确。

于 2013-03-29T16:40:22.093 回答