在下面的文章use-case 1中,它们更改了setTimeout调用在count函数中的位置:
https://javascript.info/event-loop#use-case-1-splitting-cpu-hungry-tasks
在第二种情况下,速度要快得多,他们用以下一句加以解释:
如果您运行它,很容易注意到它花费的时间要少得多。 为什么? 这很简单:正如您所记住的,对于许多嵌套的setTimeout调用,浏览器内的最小延迟为4ms。即使我们设置为0,它也是4ms (或更多)。所以我们安排的时间越早,它的运行就越快。
对我来说,这是一个非常不清楚的解释,我完全不明白它们的意思。有谁能更清楚和详细地解释为什么这两种情况需要不同的时间?
发布于 2021-11-13 11:43:19
setTimeout(fn, t)将同步调度 fn向now + t开火。
然后,引用中的解释是:如果在锁定计算机一段时间之前就安排了任务,那么它将在启动之前启动,而不是在计划完成之后。
// now = wall clock 0;
setTimeout(fn, 1000); // schedules `fn` to fire at wall clock 0 + 1000 = 1000
lockCPUFor(5000);
// now = wall clock 5000;
setTimeout(fn, 1000); // schedules `fn` to fire at wall clock 5000 + 1000 = 6000;在任务结束时,我们现在是= 5000 +几毫秒。第一个超时由4s传递,因此我们将立即执行它。然而,第二次超时计划在大约一秒钟内启动,所以我们将等待大约一秒钟。
const origin = performance.now();
function fn(name) {
console.log(name, performance.now() - origin);
}
fn("begin"); // ~0.05
setTimeout(() => fn("setTimeout before"), 1000); // ~ 5010
lockCPUFor(5000);
setTimeout(() => fn("setTimeout after"), 1000); // ~6000
function lockCPUFor(t) {
const now = performance.now();
while (performance.now() - now < t) {}
}
但是在我们的例子中,延迟是0而不是1000,所以这不重要。
正如你引用的那样,传递0并不意味着你真的会有一个零超时。有些环境(例如铬和node.js)总是有1ms的最小超时(尽管Chrome正在积极尝试会删除最小超时),火狐也会添加一些最小超时,“在页面加载时”(实际上,页面加载超时的他们有一个特殊的任务队列。比任何其他任务队列的优先级都要低)。
跟随HTML规范的每个UA在嵌套的第5层将有一个4ms的超时:
let startTime;
let i = 0;
const fn = () => {
console.log("iteration #%s took %sms", i + 1, performance.now() - startTime);
if (++i < 6) {
startTime = performance.now();
setTimeout(fn, 0);
}
}
const startTest = () => {
startTime = performance.now();
setTimeout(fn, 0)
}
// avoid Firefox's weird at-load task queue
onload = startTest;
因此,即使您通过0,这几个由UA自动添加的ms也会影响回调何时被调度,而在长任务之前的调度将确实允许避免大多数这些限制(如果长任务持续时间更长)。
但是请注意,如果您需要比setTimeout更快地连接到事件循环,那么有办法。
https://stackoverflow.com/questions/69951422
复制相似问题