时间切片

1. 下次绘制交互 (INP)

  下次绘制交互 (INP) 是一项新的指标,浏览器计划于 2024 年 3 月将其取代取代首次输入延迟 (FID) ,成为最新的 Web Core Vitals(Web 核心性能指标)。

2. 时间切片-scheduler.yield

  背景:用户任务完成自动释放控制权给主线程。而如果任务耗时过长,则可能出现延迟导致主线程任务响应延迟。那么一种解决方法就是在主线程任务到来时将线程释放,先执行主线程任务,等主线程任务完成再继续执行该任务。这个理念最早在React的Schedule中实现,现在是浏览器要开始默认支持该功能。

  在没有时间切片概念之前,其他的处理方法:setTimeout。

 1 function blockingTask (ms = 200) {
 2   let arr = [];
 3   const blockingStart = performance.now();
 4 
 5   console.log(`Synthetic task running for ${ms} ms`);
 6 
 7   while (performance.now() < (blockingStart + ms)) {
 8     arr.push(Math.random() * performance.now / blockingStart / ms);
 9   }
10 }
11 
12 function yieldToMain () {
13   return new Promise(resolve => {
14     setTimeout(resolve, 0);
15   });
16 }
17 
18 async function runTaskQueueSetTimeout () {
19   if (typeof intervalId === "undefined") {
20     alert("Click the button to run blocking tasks periodically first.");
21     
22     return;
23   }
24   
25   clearTaskLog();
26 
27   for (const item of [1, 2, 3, 4, 5]) {
28     blockingTask();
29     logTask(`Processing loop item ${item}`);
30     
31     await yieldToMain();
32   }
33 }
34 
35 document.getElementById("setinterval").addEventListener("click", ({ target }) => {
36   clearTaskLog();
37 
38   intervalId = setInterval(() => {
39     if (taskOutputLines < MAX_TASK_OUTPUT_LINES) {
40       blockingTask();
41     
42       logTask("Ran blocking task via setInterval");
43     }
44   });
45   
46   target.setAttribute("disabled", true);
47 }, {
48   once: true
49 });
50 
51 document.getElementById("settimeout").addEventListener("click", () => {
52   runTaskQueueSetTimeout();
53 });

输出:

Processing loop item 1
Processing loop item 2
Ran blocking task via setInterval
Processing loop item 3
Ran blocking task via setInterval
Processing loop item 4
Ran blocking task via setInterval
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval

  使用scheduler.yield

方法:

 1 async function yieldy () {
 2   // Do some work...
 3   // ...
 4 
 5   // Yield!
 6   await scheduler.yield();
 7 
 8   // Do some more work...
 9   // ...
10 }

示例:

 1 async function runTaskQueueSchedulerDotYield () {
 2   if (typeof intervalId === "undefined") {
 3     alert("Click the button to run blocking tasks periodically first.");
 4     
 5     return;
 6   }
 7 
 8   if ("scheduler" in window && "yield" in scheduler) {
 9     clearTaskLog();
10 
11     for (const item of [1, 2, 3, 4, 5]) {
12       blockingTask();
13       logTask(`Processing loop item ${item}`);
14 
15       await scheduler.yield();
16     }
17   } else {
18     alert("scheduler.yield isn't available in this browser :(");
19   }
20 }

输出:

Processing loop item 1
Processing loop item 2
Processing loop item 3
Processing loop item 4
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval

  

该特性在谷歌115版本才支持,兼容写法:

 1 function yieldToMain () {
 2   // Use scheduler.yield if it exists:
 3   if ('scheduler' in window && 'yield' in scheduler) {
 4     return scheduler.yield();
 5   }
 6 
 7   // Fall back to setTimeout:
 8   return new Promise(resolve => {
 9     setTimeout(resolve, 0);
10   });
11 }
12 
13 // Example usage:
14 async function doWork () {
15   // Do some work:
16   // ...
17 
18   await yieldToMain();
19 
20   // Do some other work:
21   // ...
22 }

 

Processing loop item 1
Processing loop item 2
Ran blocking task via setInterval
Processing loop item 3
Ran blocking task via setInterval
Processing loop item 4
Ran blocking task via setInterval
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
posted @ 2023-08-30 14:54  TheFirstDream  阅读(46)  评论(0编辑  收藏  举报