xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

why is the setInterval task executed slower than the setTimeout task in the browser javascript environment?

why is the setInterval task executed slower than the setTimeout task in the browser javascript environment?

为什么在浏览器 javascript 环境下 setInterval 任务执行速度比 setTimeout 任务慢?

setTimeout(() => {
  console.log(`4`);
});

let id = setInterval(() => {
  console.log(`5`);
  clearInterval(id);
});

Promise.resolve().then(() => console.log(`2`));

queueMicrotask(() => {
  console.log(`3`);
});

console.log(`1`);

/*

1
2

3
4
5

*/

image

https://stackoverflow.com/questions/75612404/why-is-the-setinterval-task-executed-slower-than-the-settimeout-task-in-the-java

Chrome bug ❓

https://bugs.chromium.org/p/chromium/issues/detail?id=1421612

??? Event Loop task priority / 事件循环任务优先级

https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#stack

https://libevent.org/

https://github.com/v8/v8

??? js event loop timers proority

https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

https://nodejs.org/zh-cn/docs/guides/event-loop-timers-and-nexttick/

https://stackoverflow.com/questions/19743354/does-javascript-event-queue-have-priority

源码

https://github.com/search?q=repo%3Av8/v8 setInterval&type=code

which includes eval(), Function(), setTimeout() and setInterval()

https://github.com/v8/v8/blob/4f632833589b37bc4c71d36180d0a31caaee9ad5/include/js_protocol.pdl#L1491

https://github.com/search?q=repo%3Av8/v8 setTimeout&type=code

image

https://github.com/v8/v8/blob/4f632833589b37bc4c71d36180d0a31caaee9ad5/include/v8-microtask-queue.h

https://github.com/v8/v8/blob/4f632833589b37bc4c71d36180d0a31caaee9ad5/include/v8-microtask.h

https://github.com/v8/v8/blob/4f632833589b37bc4c71d36180d0a31caaee9ad5/tools/system-analyzer/log/timer.mjs#L4

https://github.com/v8/v8/blob/4f632833589b37bc4c71d36180d0a31caaee9ad5/tools/system-analyzer/view/timeline/timeline-track-timer.mjs#L4

源码解析

https://github.com/learning-js-by-reading-source-codes/v8

setTimeout 定时器时间不准确 bug ❌

let startTime = new Date();
setTimeout(() => {
  let endTime = new Date();
  console.log(endTime - startTime);
}, 0);
for (let i = 0; i < 10**6; i++) {
   // 任务中的同步代码执行时间过长,导致异步宏任务 setTimeout 的执行时间延后 bug
}

Firefox enforces additional throttling for scripts that it recognizes as tracking scripts.
When running in the foreground, the throttling minimum delay is still 4ms.
In background tabs, however, the throttling minimum delay is 10,000 ms, or 10 seconds, which comes into effect 30 seconds after a document has first loaded.

Firefox 对其识别为跟踪脚本的脚本实施额外的限制。
在前台运行时,throttling 最小延迟仍然是 4ms
但是,在后台选项卡中,最小延迟限制为 10,000 毫秒10 秒,它在文档首次加载 30 秒后生效。

https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#throttling_of_tracking_scripts

Maximum delay value Browsers store the delay as a 32-bit signed integer internally. This causes an integer overflow when using delays larger than 2,147,483,647 ms (about 24.8 days), resulting in the timeout being executed immediately.

最大延迟值 浏览器在内部将延迟存储为 32 位有符号整数。当使用大于 2,147,483,647 毫秒(约 24.8 天)的延迟时,这会导致整数溢出,导致立即执行超时。

https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value

setInterval delay bug ❌

// 高精度时间戳

https://developer.mozilla.org/en-US/docs/Web/API/setInterval#delay_restrictions

HTML Standard

Timers can be nested;
after five such nested timers, however, the interval is forced to be at least four milliseconds.
定时器可以嵌套;
然而,在五个这样的嵌套定时器之后,间隔被强制至少为四毫秒。

This API does not guarantee that timers will run exactly on schedule.
Delays due to CPU load, other tasks, etc, are to be expected.
此 API 不保证计时器将完全按计划运行。
由于 CPU 负载、其他任务等导致的延迟是可以预料的。

https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers

The timer initialization steps
定时器初始化步骤

The task's timer nesting level is used both for nested calls to setTimeout(), and for the repeating timers created by setInterval(). (Or, indeed, for any combination of the two.) In other words, it represents nested invocations of this algorithm, not of a particular method.

任务的计时器嵌套级别既用于对 setTimeout() 的嵌套调用,也用于由 setInterval() 创建的重复计时器。 (或者,实际上,对于两者的任意组合。)换句话说,它表示此算法的嵌套调用,而不是特定方法的嵌套调用。

  1. Let thisArg be global if that is a WorkerGlobalScope object; otherwise let thisArg be the WindowProxy that corresponds to global.
  2. If previousId was given, let id be previousId; otherwise, let id be an implementation-defined integer that is greater than zero and does not already exist in global's map of active timers.
  3. If the surrounding agent's event loop's currently running task is a task that was created by this algorithm, then let nesting level be the task's timer nesting level. Otherwise, let nesting level be zero.
  4. If timeout is less than 0, then set timeout to 0.
  5. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.
  6. Let realm be global's relevant realm.
  7. Let initiating script be the active script.
  8. Assert: initiating script is not null, since this algorithm is always called from some script.
  9. Let task be a task that runs the following substeps:

image

  1. Increment nesting level by one.
  2. Set task's timer nesting level to nesting level.
  3. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
  4. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id.
  5. Return id.

https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout

使用 requestAnimationFrame 获取更可靠的定时器`时间

// 性能优化
// 16ms ❓60Hz/s 刷新率, js 动画高性能更新策略

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

requestIdleCallback

Deferral of timeouts during pageload

延迟页面加载期间的超时

// 性能优化

https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#deferral_of_timeouts_during_pageload

https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback

js 获取时间戳差值的小技巧

let startTime = new Date();

let endTime = new Date();

console.log(endTime - startTime);
// 7513

startTime;
// Thu Mar 02 2023 14:27:16 GMT+0800 (China Standard Time)
startTime - 0;
// 1677738436958

endTime;
// Thu Mar 02 2023 14:27:24 GMT+0800 (China Standard Time)
endTime - 0;
// 1677738444471

endTime - startTime;
// 7513

(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!

refs

https://www.cnblogs.com/xgqfrms/p/17170304.html#5154379

https://github.com/xgqfrms/learning/issues/144



©xgqfrms 2012-2021

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2023-03-02 14:57  xgqfrms  阅读(16)  评论(4编辑  收藏  举报