javascript settimeout有多准确

时间:2016-06-25 15:42:45

标签: javascript timer

我想知道javascript中setTimeout方法的准确性。它是否具有任何超过阈值的阈值,它将完全推迟这么多毫秒,或者它是否完全执行指定的功能而不管毫秒值。

3 个答案:

答案 0 :(得分:8)

JavaScript没有setTimeout方法。浏览器和运行JavaScript的其他一些环境。

HTML5规范为§6.4- Timers中的浏览器setTimeout及其堂兄弟(通常称为“计时器”)制定了规则。

一般情况下,计时器会合理地 ,只要其回调需要运行的线程不忙于执行其他操作。但这是一个很大的附带条件。如果线程忙,则无法运行回调并且将在作业队列中等待,直到线程到达它,因此您无法确定它是否会在预期时触发,特别是如果您正在使用默认线程JavaScript在浏览器中运行,用于处理UI。它不会运行之前的 1 ,但它可能会比您预期的更晚运行。

浏览器还会更改计时器在运行窗口时以各种方式运行的方式(例如,它是非活动选项卡)。

这是一个片段,用于衡量您的浏览器在主UI线程上的效果:

var results = [];
var disp = {
    min: document.getElementById("min").firstChild,
    max: document.getElementById("max").firstChild,
    avg: document.getElementById("avg").firstChild,
    count: document.getElementById("count").firstChild
};

var now = (function() {
    if (typeof performance !== "undefined" && performance.now) {
        return function() {
            return performance.now();
        };
    }
    return function() {
        return Date.now();
    };
})();

function test() {
    var delay = Math.floor(Math.random() * 50) + 10;
    var start = now();
    setTimeout(function() {
        var elapsed = now() - start;
        var result = {
            delay: delay,
            elapsed: elapsed,
            diff: elapsed - delay
        };
        logResult(result);
        results.push(result);
        if (results.length <= 500) {
            test();
        }
    }, delay)
}

function log(msg, atTop) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    if (atTop) {
        p.style.borderBottom = "1px solid black";
        document.body.insertBefore(p, document.body.firstChild);
    } else {
        document.body.appendChild(p);
    }
}

function logResult(r) {
    log("expected " + r.delay + ", got " + r.elapsed + ", diff: " + r.diff);
    summary();
}

function summary() {
    var sum = 0,
        min = Infinity,
        max = -Infinity;
    results.forEach(function(r) {
        var d = r.diff;
        sum += d;
        min = Math.min(min, d);
        max = Math.max(max, d);
    });
    disp.min.nodeValue = min.toFixed(4);
    disp.max.nodeValue = max.toFixed(4);
    disp.avg.nodeValue = (sum / results.length).toFixed(4);
    disp.count.nodeValue = results.length;
}

setTimeout(test, 500);
.summary {
  border-bottom: 1px solid #ddd;
  padding-bottom: 4px;
}
<div class="summary">
Variance in milliseconds:
<br>
Min: <span id="min">-</span> |
Max: <span id="max">-</span> |
Avg: <span id="avg">-</span> |
Count: <span id="count">-</span>
</div>

1 “...它将无法运行之前的 ...” - 显然(来自上面的代码段)在Firefox上可以提前几分之一毫秒。我把它归结为计时器在整整几毫秒内工作的事实。显然如果你在12:30:04.0415(在12:30:04和41ms后半毫秒)安排一个计时器20ms,它将在12:30:04.061(12:30:04再加上61ms)开始计时比等到12:30:04.0615(12:30:04再加上61.5ms)。例如,显然它需要12:30:04.0415,忽略得到12:30:04.041的小数毫秒,加上20到12:30:04.061,然后在它之后尽快开火。

答案 1 :(得分:1)

您应该假设任何超时功能将等待“至少”指定的时间段。但它可能会更长。 “多长时间”是不可预测的。

答案 2 :(得分:1)

取决于实施和环境。

有许多因素,例如浏览器端,非活动标签和用户设置,服务器端和操作系统交互。