如何将客户端网页计时器与服务器同步

时间:2022-02-18 15:25:05

What is the best way to synchronise the time on a webpage with the server?

将网页上的时间与服务器同步的最佳方法是什么?

My webpage needs to start a countdown at the same time for all users, and and end at exactly the same time to prevent any one user having a slight time advantage.

我的网页需要同时为所有用户开始倒计时,并在完全相同的时间结束,以防止任何一个用户有轻微的时间优势。

My problem is similar to this question but the accepted answer helps but does not fully answer my concerns: how-to-sync-a-javascript-countdown-with-server-time

我的问题类似于这个问题但是接受的答案有帮助,但没有完全回答我的担忧:如何同步-javascript-倒计时与服务器时间

I use Ajax after pageload to get the server time, but am I guaranteed over 15 minutes that the countdown will end at exactly the same time for each client?

我在页面加载后使用Ajax来获取服务器时间,但我保证在15分钟内倒计时将在每个客户端完全相同的时间结束吗?

Even if the timers accurately measure the time, there could still be a discrepancy of just under 1 second between client pages caused by disregarding the milliseconds for the setInterval - is there any way to overcome this?

即使定时器准确地测量时间,由于忽略setInterval的毫秒数而导致客户端页面之间仍然存在不到1秒的差异 - 有什么方法可以克服这个问题吗?

3 个解决方案

#1


3  

In modern browsers, you can achieve this by assigning a timestamp to a JavaScript variable, and use the Performance object to calculate the exact time.

在现代浏览器中,您可以通过为JavaScript变量分配时间戳来实现此目的,并使用Performance对象来计算确切的时间。

Example:

var tsp = new Date('Sun Feb 19 2012 17:55:14 GMT+0100 (CET)'); // "Timestamp"

window.onload = function() {
    var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
    tsp.setTime(tsp.getTime() + performance.timing.loadEventStart - performance.timing.navigationStart
    // after window.onload, you're sync with the server

    // Example of timer:
    setInterval(function() {
        tsp.setSeconds(tsp.getSeconds() + 1);
        document.title = tsp.toString();
    }, 1000); // 1000 ms = timer may be off by 500ms.
};

For more information on this object, have a look at the MDN's article.
A demo is provided here.

有关此对象的更多信息,请查看MDN的文章。这里提供了一个演示。

#2


8  

The accepted answer is good and helped inspire me as I wrote a library to solve this problem. The library yields more precise answers by looking at the load times of itself, rather than the whole page (as done with performance.timing above) and then gets even better precision by following with a series of 10 XMLHttpRequests. Also, addressing your second concern, my library doesn't disregard the milliseconds (as does the accepted answer).

接受的答案是好的,并帮助激励我,因为我写了一个库来解决这个问题。通过查看自身的加载时间而不是整个页面(与上面的performance.timing一样),库可以产生更精确的答案,然后通过一系列10个XMLHttpRequests获得更好的精度。此外,解决您的第二个问题,我的库不会忽略毫秒(如接受的答案)。

The library is called ServerDate and is freely available.

该库名为ServerDate,可免费使用。

Here's part of the README:

这是自述文件的一部分:

You can use ServerDate as you would use the Date function or one of its instances, e.g.:

您可以像使用Date函数或其中一个实例一样使用ServerDate,例如:

> ServerDate()
"Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

> ServerDate.now()
1344900478753

> ServerDate.getMilliseconds()
22

There is also a new method to get the precision of ServerDate's estimate of the server's clock (in milliseconds):

还有一种新方法可以获得ServerDate估计服务器时钟的精度(以毫秒为单位):

> ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
"Tue Aug 14 01:01:49 2012 ± 108 ms"

You can see the difference between the server's clock and the browsers clock, in milliseconds:

您可以看到服务器的时钟和浏览器时钟之间的差异,以毫秒为单位:

> ServerDate - new Date()
39

#3


2  

Ideally your solution would involve the server sending out the signal that the submit form is open to all clients at the same time. For that you could use web sockets if you have no problem with excluding people with older browsers. There are also fallbacks using long polling for those browsers.

理想情况下,您的解决方案将涉及服务器发出提交表单同时向所有客户开放的信号。为此,如果您排除使用旧浏览器的人没有问题,您可以使用网络套接字。对于那些浏览器,还有使用长轮询的回退。

I am not sure how well websockets do together with PHP though.

我不确定websockets与PHP一起做得多好。

I've only ever used socket.io together with node JS. With that solution it would be trivial to set a server-side timeout and notify all clients at the same time when it's complete. It automatically detects the browser support and chooses a method that works best for a given browser.

我只使用socket.io和节点JS。使用该解决方案,设置服务器端超时并在完成时同时通知所有客户端将是微不足道的。它会自动检测浏览器支持并选择最适合给定浏览器的方法。

Using this solution the clients will only ever allow submissions when the server has told them it is ready. As long as the server you submit to performs validation you should be fine.

使用此解决方案,客户端将只允许在服务器告知它已准备好时提交。只要您提交的服务器执行验证,您就可以了。

#1


3  

In modern browsers, you can achieve this by assigning a timestamp to a JavaScript variable, and use the Performance object to calculate the exact time.

在现代浏览器中,您可以通过为JavaScript变量分配时间戳来实现此目的,并使用Performance对象来计算确切的时间。

Example:

var tsp = new Date('Sun Feb 19 2012 17:55:14 GMT+0100 (CET)'); // "Timestamp"

window.onload = function() {
    var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
    tsp.setTime(tsp.getTime() + performance.timing.loadEventStart - performance.timing.navigationStart
    // after window.onload, you're sync with the server

    // Example of timer:
    setInterval(function() {
        tsp.setSeconds(tsp.getSeconds() + 1);
        document.title = tsp.toString();
    }, 1000); // 1000 ms = timer may be off by 500ms.
};

For more information on this object, have a look at the MDN's article.
A demo is provided here.

有关此对象的更多信息,请查看MDN的文章。这里提供了一个演示。

#2


8  

The accepted answer is good and helped inspire me as I wrote a library to solve this problem. The library yields more precise answers by looking at the load times of itself, rather than the whole page (as done with performance.timing above) and then gets even better precision by following with a series of 10 XMLHttpRequests. Also, addressing your second concern, my library doesn't disregard the milliseconds (as does the accepted answer).

接受的答案是好的,并帮助激励我,因为我写了一个库来解决这个问题。通过查看自身的加载时间而不是整个页面(与上面的performance.timing一样),库可以产生更精确的答案,然后通过一系列10个XMLHttpRequests获得更好的精度。此外,解决您的第二个问题,我的库不会忽略毫秒(如接受的答案)。

The library is called ServerDate and is freely available.

该库名为ServerDate,可免费使用。

Here's part of the README:

这是自述文件的一部分:

You can use ServerDate as you would use the Date function or one of its instances, e.g.:

您可以像使用Date函数或其中一个实例一样使用ServerDate,例如:

> ServerDate()
"Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

> ServerDate.now()
1344900478753

> ServerDate.getMilliseconds()
22

There is also a new method to get the precision of ServerDate's estimate of the server's clock (in milliseconds):

还有一种新方法可以获得ServerDate估计服务器时钟的精度(以毫秒为单位):

> ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
"Tue Aug 14 01:01:49 2012 ± 108 ms"

You can see the difference between the server's clock and the browsers clock, in milliseconds:

您可以看到服务器的时钟和浏览器时钟之间的差异,以毫秒为单位:

> ServerDate - new Date()
39

#3


2  

Ideally your solution would involve the server sending out the signal that the submit form is open to all clients at the same time. For that you could use web sockets if you have no problem with excluding people with older browsers. There are also fallbacks using long polling for those browsers.

理想情况下,您的解决方案将涉及服务器发出提交表单同时向所有客户开放的信号。为此,如果您排除使用旧浏览器的人没有问题,您可以使用网络套接字。对于那些浏览器,还有使用长轮询的回退。

I am not sure how well websockets do together with PHP though.

我不确定websockets与PHP一起做得多好。

I've only ever used socket.io together with node JS. With that solution it would be trivial to set a server-side timeout and notify all clients at the same time when it's complete. It automatically detects the browser support and chooses a method that works best for a given browser.

我只使用socket.io和节点JS。使用该解决方案,设置服务器端超时并在完成时同时通知所有客户端将是微不足道的。它会自动检测浏览器支持并选择最适合给定浏览器的方法。

Using this solution the clients will only ever allow submissions when the server has told them it is ready. As long as the server you submit to performs validation you should be fine.

使用此解决方案,客户端将只允许在服务器告知它已准备好时提交。只要您提交的服务器执行验证,您就可以了。