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