時間切片

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章