我正在开发一个对时间敏感的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应用程序可能会一次打开几天。
如何修改此代码,以便网络浏览器能够持续准确地显示服务器的时间?
答案 0 :(得分:6)
Javascript的setInterval不够准确,无法像这样保留时间。
我的解决方案是:
编辑: 为了更准确,您可以测量服务器请求的往返时间,将其除以2并将该延迟计入时钟偏差。假设往返行程的持续时间是对称的,这将给出更准确的计算。
答案 1 :(得分:2)
setInterval
不是安排时间关键事件的可靠方法。运行回调可能需要少于或多于1000ms
,具体取决于当前JavaScript的繁忙程度。
更好的方法是缩短间隔并使用new Date().getTime()
检查是否已经过了一段时间。
浏览器允许的最小间隔为10
。
答案 2 :(得分:0)
感谢您的回答。到目前为止,我已经对两个答案进行了投票,因为它们包含有用的信息。但是,我没有使用任何一个答案中规定的确切答案。
我最终决定的是有点不同。
我写了关于我在personal web page上学到的内容。
首先,我现在明白使用setInterval(..., 1000)
并不足以让我们长时间每秒做一次事情。然而,以更短的间隔'轮询'时间寻找第二个改变对我来说似乎非常低效。
我认为跟踪服务器时间和客户端时间之间的“偏移量”确实很有意义。
我的最终解决方案是执行以下操作:
(1)对服务器进行AJAX调用以获取时间。该功能还会检查客户端时间并计算服务器时间和客户端时间之间的差异(以毫秒为单位)。由于网络延迟和其他因素,此初始提取可能会关闭几秒钟。就我的目的而言,这没关系。
(2)执行tick
功能。每次tick
执行时,它会检查自上次执行tick
以来的时间长度。它将使用这段时间来计算要传递给setTimeout
的参数,以便时间显示大约每秒更新一次。
(3)每次tick
函数计算要显示的时间时,它会花费客户端时间并添加在步骤(1)中计算的差异。这样,我不依赖于客户端正确设置时间,但我确实依赖于客户端来准确测量经过的时间。就我的目的而言,这没关系。最重要的是,无论setTimeout
如何被其他进程(例如模态对话框)不准确或中断,显示的时间应始终准确。