Javascript计时器的准确性

时间:2012-01-27 18:14:39

标签: php javascript timer

请注意,这是我之前的一个后续问题:“How to memorize user's progress through the application?”。

在答案之后,我明白错误是使用Javascript来确定用户是否赢得了比赛。所以我将逻辑移到我的控制器中:当用户启动关卡时,我将UNIX时间戳保存到会话中,并在用户结束时计算差异。如果用户完成关卡的时间不超过X秒,我允许他/她访问下一个,依此类推。

一切正常,直到我决定引入用Javascript制作的客户端计时器。计时器显然不像PHP那样准确,因为它依赖于用户的CPU而不是服务器的CPU。因此,两个定时器不同步。当时间范围很大时(例如,用户必须完成4到10秒之间的水平),游戏仍然有效,但是当时间范围较小(1或2秒)时,它不能按预期工作。即使用户在获胜时间框架内点击,PHP也会告诉他他没有获胜。

我做了一些尝试,这是我的结果:

|===========================|
| # |  PHP  |   JS  | Ratio |
|===========================|
| 1 |  6.20 |  5.29 |  1.17 |
| 2 |  7.32 |  6.27 |  1.16 |
| 3 |  2.89 |  2.24 |  1.29 |
| 4 | 22.56 | 20.13 |  1.12 |
| 5 | 50.15 | 45.24 |  1.10 |
|===========================|

(是的,我知道,这是有史以来最糟糕的ASCII表。)

这是我使用jQuery制作的计时器(我没有用这种语言练习过,所以它可能也是有史以来最糟糕的Javascript计时器):

$(document).ready(function() {
    window['time'] = {
        'cseconds': 0,
        'dseconds': 0,
        'seconds': 0,
        'minutes': 0,
        'hours': 0
    };

    $("#timer").everyTime(10, function() {
        window['time']['cseconds'] += 1;

        if (window['time']['cseconds'] > 9) {
            window['time']['cseconds'] = 0;
            window['time']['dseconds'] += 1;
        }

        if (window['time']['dseconds'] > 9) {
            window['time']['dseconds'] =  0;
            window['time']['seconds']  += 1;
        }

        if (window['time']['seconds'] > 60) {
            window['time']['seconds'] =  0;
            window['time']['minutes'] += 1;
        }

        if (window['time']['minutes'] > 60) {
            window['time']['minutes'] =  0;
            window['time']['hours']   += 1;
        }

        cseconds = window['time']['cseconds'].toString();
        dseconds = window['time']['dseconds'].toString();
        seconds  = window['time']['seconds'].toString();
        minutes  = window['time']['minutes'].toString();
        hours    = window['time']['hours'].toString();

        if (seconds.length < 2) {
            seconds = "0" + seconds;
        }
        if (minutes.length < 2) {
            minutes = "0" + minutes;
        }
        if (hours.length < 2) {
            hours = "0" + hours;
        }

        $("#timer").text(hours + ":" + minutes + ":" + seconds + "." + dseconds + cseconds);
    });
});

我尝试过不同的解决方案,比如AJAX:首先,计时器仅依赖于AJAX请求(导致数千个HTTP请求),但仍然不精确。然后我修改它以每隔X秒与PHP同步,但它也不起作用。

有没有人有任何提示?

3 个答案:

答案 0 :(得分:3)

如果您通过在事件的开始和结束时执行new Date()计时事件并比较它们之间的经过时间差异,您将使用javascript获得非常准确的计时。现代浏览器中定时器的精度通常为几毫秒,而旧版浏览器的定时器精度不低于15毫秒。

您的代码看起来像是在尝试使用间隔计时器并计算间隔。这不会很准确。因为javascript是单线程的,所以javascript计时器触发的确切时间不是非常精确,因此不应该依赖于事件的准确计时。换句话说,测量已用系统时间而不是计算已触发的计时器间隔要准确得多。

答案 1 :(得分:1)

为什么AJAX解决方案不起作用?这是我心中的第二个解决方案。它必须工作,因为时间来自服务器......

第一个解决方案非常简单,我认为最准确。而不是依赖于Javascript定期执行功能,尝试依赖系统日期时间。使用Javascript周期性功能更新屏幕上的时间,但使用系统日期/时间而不是简单的seconds += 1来获取时间!一些伪代码:

var startTime = new Date();

// Every 1/2 second or less...
var elapsedTimeInMs = new Date().getTime() - startTime.getTime();

但我建议您阅读Date个对象的文档。

答案 2 :(得分:0)

你将不得不使用AJAX,但只有在用户完成游戏的情况下,才能获得服务器上的时间......