javascript settimeout有多准确

Shy*_*r R 1 javascript timer

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

T.J*_*der 8

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

HTML5规范setTimeout§6.4-计时器中的浏览器规定了规则及其表兄弟(通常称为 "计时器").

通常,如果其回调需要运行的线程不忙于执行其他操作,则计时器将合理准确地触发.但这是一个很大的附带条件.如果线程忙,则无法运行回调并且将在作业队列中等待,直到线程到达它,因此您无法确定它是否会在预期时触发,特别是如果您正在使用默认线程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);
Run Code Online (Sandbox Code Playgroud)
.summary {
  border-bottom: 1px solid #ddd;
  padding-bottom: 4px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


1 "......它不会提前运行......" - 显然(来自上面的代码片段)在Firefox上它可以提前运行一小部分.我把它归结为计时器在整整几毫秒内工作的事实.很显然,如果你安排在12定时器:30:30::(正好12点30个04秒加上61ms)04.061,而对于20毫秒(12点30分04秒和41ms后半毫秒)04.0415,它会在12火了比等到12:30:04.0615(12:30:04再加上61.5ms).此后04.061,并立即触发,因为它可以:例如,显然需要花费12:30:04.0415,忽略小数毫秒获得12:30:04.041,增加了20至12获得:30.