postTask:React 的殺手鐧被瀏覽器原生實現了?
React
這幾年一直在完善的**「併發模式」**主要由以下兩部分組成:
-
基於
fiber
實現的可中斷更新的架構 -
基於調度器的優先級調度
可以說,從 16 年開始重構fiber
架構到今年底(或明年初)React18
發佈正式版,這期間React
團隊大部分工作都是圍繞這兩點展開的。
如果現在告訴你,React
嘔心瀝血多年實現的**「優先級調度」**,瀏覽器原生就支持,會不會很驚訝?
文章參考 Building a Faster Web Experience with the postTask Scheduler[1]。
什麼是優先級調度
假設,我們有個**「記錄日誌」**的腳本需要在頁面初始化後執行:
initCriticalTracking();
調用棧火炬圖如下:
可以看到,這是個執行了 249.08ms 的長任務,在執行期間瀏覽器會掉幀(表現爲:瀏覽器卡頓)。
現在,我們將其包裹在**「優先級調度函數 scheduler.postTask」**的回調函數中:
scheduler.postTask(() => initCriticalTracking());
長任務被分解爲多個短任務:
在每個任務之間瀏覽器有機會重排、重繪,減少了掉幀的可能性。
這種**「根據任務優先級將任務拆解,分配執行時間的技術」**,就是**「優先級調度」**。
scheduler.postTask[2] 是Chrome
實現的**「優先級調度 API」**。
scheduler.postTask 屬於試驗功能,需要在 chrome://flags 中打開 #enable-experimental-web-platform-features
之前是如何實現優先級調度的
在scheduler.postTask
出現之前,通常使用瀏覽器提供的**「會在不同階段調用的 API」**模擬**「優先級調度」**,比如:
-
requestAnimationFrame
(簡稱rAF
)一般用來處理動畫,會在瀏覽器渲染前觸發 -
requestIdleCallback
(簡稱rIC
)在每一幀沒有其他任務的空閒時間調用 -
setTimeout
、postMessage
、MessageChannel
在渲染之間觸發
React
使用MessageChannel
實現優先級調度,setTimeout
作爲降級方案。
但是,這些API
畢竟都有本職工作。用他們實現的**「優先級調度」**比較粗糙。
基於此原因,postTask Scheduler
誕生了。
postTask Scheduler 的使用
scheduler.postTask
有 3 種可選優先級:
使用方式很簡單,通過以下方式註冊的回調函數會以**「默認優先級」**調度:
// 默認優先級
scheduler.postTask(() => console.log('Hello, postTask'));
你也可以指定優先級與執行延遲:
// 調用後延遲1秒執行,優先級最低
scheduler.postTask(() => console.log('Hello, postTask'), {
delay: 1000,
priority: 'background',
});
postTask
建立在 AbortSignal API[3] 上,所以我們可以取消尚在排隊還未執行的回調函數。
通過使用TaskController API
控制:
const controller = new TaskController('background');
window.addEventListener('beforeunload', () => controller.abort());
scheduler.postTask(() => console.log('Hello, postTask'), {
signal: controller.signal,
});
同時,實驗性的schedule.wait
方法可以讓我們輕鬆的等待某一時機後再執行任務。
比如,我們可以在頁面加載完成後異步加載xxx.js
:
async function loadxxx() {
// 等待事件被派發
await scheduler.wait('myPageHasLoaded');
return import('xxx.js');
}
// 頁面加載後派發事件
window.dispatchEvent(new CustomEvent('myPageHasLoaded'));
以上代碼被簡化爲postTask
的event
配置項:
scheduler.postTask(() => import('xxx.js'), {
event: 'myPageHasLoaded'
})
總結
**「優先級調度」**可以應用在很多領域,比如:
-
資源提前、延後請求
-
第三方資源延遲加載
......
可以預見,未來這勢必會增加前端編程複雜度。
就像曾經,當web
應用複雜到一定程度時,出現了前端框架,開發者不用直接操作DOM
。
未來,當**「優先級調度」**複雜到一定程度時,一定也會出現集成解決方案,讓開發者不用直接操作優先級
。
慢着,這不就是React
現在在做的事麼?
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ZW4kwSYelnuUA0grKQmXow