【问题标题】:Will setInterval drift?setInterval 会漂移吗?
【发布时间】:2010-11-02 09:48:45
【问题描述】:

这确实是一个非常简单的问题。如果我使用setInterval(something, 1000),我是否可以完全确定在 31 天之后它会准确地触发“某事”60*60*24*31 次?或者所谓的漂移有风险吗?

【问题讨论】:

    标签: javascript setinterval


    【解决方案1】:

    简短回答:不,你不能确定。是的,它可以漂移。

    长答案:Accuracy of JavaScript TimeHow JavaScript Timers Work 上的 John Resig。

    来自第二篇:

    为了了解计时器在内部的工作方式,需要探索一个重要的概念:计时器延迟无法保证。由于浏览器中的所有 JavaScript 都在单个线程上执行,因此异步事件(例如鼠标点击和计时器)仅在执行有空位时运行。

    这两篇文章(以及该网站上的任何内容)都非常适合阅读,因此请阅读。

    【讨论】:

    • 我不明白。在第二篇文章中,John Resig 说“...setInterval 将尝试每 10 毫秒执行一次回调,无论上次回调何时执行。”这意味着 setInterval 没有漂移。
    • 它会尝试,但如果在 10 毫秒后执行被另一个长时间运行的函数阻塞,它会漂移。另一个(愚蠢的)例子:如果你每 10 毫秒执行一次的函数需要 11 毫秒才能运行呢?第二个函数什么时候运行?我相信 20 毫秒后(10 毫秒开始会跳过)
    • 基本上,更简单的说法是用户事件(单击鼠标)可以在计时器结束时发生,这可以中断该结束事件。当定时器应该关闭时,它可以占用该进程打开 CPU 的时间。
    • @chowey——虽然 Resig 的声明对于某些实现(例如 Chrome、Opera)可能是正确的,但在其他实现(例如 Safari、Firefox)中显然是错误的。
    【解决方案2】:

    这是您可以在 Firefox 中运行的基准测试:

    var start = +new Date();
    var count = 0;
    setInterval(function () {
        console.log((new Date() - start) % 1000,
        ++count,
        Math.round((new Date() - start)/1000))
    }, 1000);
    

    第一个值应尽可能接近 0 或 1000(任何其他值都显示触发的时间有多“离场”。)第二个值是代码被触发的次数,第三个值是应该被触发了多少次。你会注意到,如果你占用你的 CPU,它可能会离场,但它似乎会自行纠正。尝试运行更长的时间,看看它是如何处理的。

    【讨论】:

    • 这是上面的实时版本,稍作调整以在浏览器中显示输出并且更清晰:jsfiddle.net/hqmLg/1
    • 它永远不会为我纠正自己。如果我每秒执行 100 次之类的操作,它会执行 ~85 次,但如果我输入控制台日志,它会加速 ~30 次。 - jsfiddle.net/pajtai/qXkNY(使用 Phrogz 演示)
    • 好吧,我上面所做的测试是在一台 10 岁左右的 32 位笔记本电脑上的 Ubuntu FF 上进行的。我在一台新的 64 位 Windows 机器上试了一下,FF 更接近了。 IE 和 Chrome 平均在十分之二以内。
    • driftlesssetInterval 的替代品,可减轻漂移。
    【解决方案3】:

    (对不起我的英语不好) 我在倒计时函数方面遇到了同样的问题,我编写了一个函数 countdown() 并使用 setInterval 循环,但它每个循环漂移 1-3 毫秒。然后我写了一个函数来控制是否有任何漂移并修复它。

    它只控制真正的分钟和秒。这里是。它对我来说很好,我希望它也能帮助你。

    $.syncInterval(functionname,interval,controlinterval)
    

    示例:

    countdown(){ some code };
    $.syncInterval(countdown,1000,60);
    

    它说每 1000 毫秒运行一次倒计时功能并每 60 秒检查一次

    代码如下:

    $.syncInterval = function (func,interval,control) { 
            var 
            now=new Date();
            realMinute=now.getMinutes(),
            realSecond=now.getSeconds(),
            nowSecond=realSecond,
            nowMinute=realMinute,
            minuteError=0,
            countingVar=1,
            totalDiff=0;
    
            var loopthat = setInterval(function(){
    
            if (nowSecond==0) {
                nowMinute++;
                nowMinute=nowMinute%60;
            };
            if (countingVar==0){
    
                now=new Date();
                realSecond=now.getSeconds();
                realMinute=now.getMinutes();
    
                totalDiff=((realMinute*60)+(realSecond))-((nowMinute*60)+(nowSecond));
                if(totalDiff>0){
                    for (i=1;i<=totalDiff;i++) {
                        func();
                        nowSecond++;
                        countingVar++;
                    };
                } else if (totalDiff==0){
                    func();
                    nowSecond++;
                    countingVar++;
                } else if (totalDiff<0) {
    
                };
            } else {
                func();
                nowSecond++;
                countingVar++;
            };
            countingVar=countingVar%control;
            nowSecond=nowSecond%60;
        },interval);
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      • 2017-07-08
      • 2019-10-18
      • 2012-12-11
      • 1970-01-01
      相关资源
      最近更新 更多