1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        postTask:React的殺手锏被瀏覽器原生實(shí)現(xiàn)了?

        共 3106字,需瀏覽 7分鐘

         ·

        2021-10-02 00:29

        點(diǎn)擊獲取招聘信息:螞蟻體驗(yàn)技術(shù)部招前端

        React這幾年一直在完善的「并發(fā)模式」主要由以下兩部分組成:

        • 基于fiber實(shí)現(xiàn)的可中斷更新的架構(gòu)

        • 基于調(diào)度器的優(yōu)先級(jí)調(diào)度

        可以說(shuō),從16年開(kāi)始重構(gòu)fiber架構(gòu)到今年底(或明年初)React18發(fā)布正式版,這期間React團(tuán)隊(duì)大部分工作都是圍繞這兩點(diǎn)展開(kāi)的。

        如果現(xiàn)在告訴你,React嘔心瀝血多年實(shí)現(xiàn)的「優(yōu)先級(jí)調(diào)度」,瀏覽器原生就支持,會(huì)不會(huì)很驚訝?

        文章參考Building a Faster Web Experience with the postTask Scheduler[1]。

        什么是優(yōu)先級(jí)調(diào)度

        假設(shè),我們有個(gè)「記錄日志」的腳本需要在頁(yè)面初始化后執(zhí)行:

        initCriticalTracking();

        調(diào)用?;鹁鎴D如下:

        可以看到,這是個(gè)執(zhí)行了249.08ms的長(zhǎng)任務(wù),在執(zhí)行期間瀏覽器會(huì)掉幀(表現(xiàn)為:瀏覽器卡頓)。

        現(xiàn)在,我們將其包裹在「優(yōu)先級(jí)調(diào)度函數(shù)scheduler.postTask」的回調(diào)函數(shù)中:

        scheduler.postTask(() => initCriticalTracking());

        長(zhǎng)任務(wù)被分解為多個(gè)短任務(wù):

        在每個(gè)任務(wù)之間瀏覽器有機(jī)會(huì)重排、重繪,減少了掉幀的可能性。

        這種「根據(jù)任務(wù)優(yōu)先級(jí)將任務(wù)拆解,分配執(zhí)行時(shí)間的技術(shù)」,就是「優(yōu)先級(jí)調(diào)度」。

        scheduler.postTask[2]Chrome實(shí)現(xiàn)的「優(yōu)先級(jí)調(diào)度API」

        scheduler.postTask屬于試驗(yàn)功能,需要在 chrome://flags 中打開(kāi) #enable-experimental-web-platform-features

        之前是如何實(shí)現(xiàn)優(yōu)先級(jí)調(diào)度的

        scheduler.postTask出現(xiàn)之前,通常使用瀏覽器提供的「會(huì)在不同階段調(diào)用的API」模擬「優(yōu)先級(jí)調(diào)度」,比如:

        • requestAnimationFrame(簡(jiǎn)稱(chēng)rAF)一般用來(lái)處理動(dòng)畫(huà),會(huì)在瀏覽器渲染前觸發(fā)

        • requestIdleCallback(簡(jiǎn)稱(chēng)rIC)在每一幀沒(méi)有其他任務(wù)的空閑時(shí)間調(diào)用

        • setTimeoutpostMessage、MessageChannel在渲染之間觸發(fā)

        React使用MessageChannel實(shí)現(xiàn)優(yōu)先級(jí)調(diào)度,setTimeout作為降級(jí)方案。

        但是,這些API畢竟都有本職工作。用他們實(shí)現(xiàn)的「優(yōu)先級(jí)調(diào)度」比較粗糙。

        基于此原因,postTask Scheduler誕生了。

        postTask Scheduler的使用

        scheduler.postTask有3種可選優(yōu)先級(jí):

        優(yōu)先級(jí)描述polyfill實(shí)現(xiàn)
        user-blocking最高優(yōu)先級(jí),可能會(huì)阻塞用戶(hù)交互使用 MessageChannel 調(diào)度任務(wù), setTimeout作為降級(jí)方案
        user-visible第二優(yōu)先級(jí),對(duì)用戶(hù)可見(jiàn),但不會(huì)阻塞用戶(hù)交互。比如:渲染第二屏內(nèi)容。這是默認(rèn)優(yōu)先級(jí)在 user-blocking 實(shí)現(xiàn)的基礎(chǔ)上通過(guò)優(yōu)先級(jí)隊(duì)列控制
        background最低優(yōu)先級(jí),通常執(zhí)行不緊急任務(wù),例如記錄日志使用 rIC 實(shí)現(xiàn),setTimeout(0)作為降級(jí)方案

        使用方式很簡(jiǎn)單,通過(guò)以下方式注冊(cè)的回調(diào)函數(shù)會(huì)以「默認(rèn)優(yōu)先級(jí)」調(diào)度:

        // 默認(rèn)優(yōu)先級(jí)
        scheduler.postTask(() => console.log('Hello, postTask'));

        你也可以指定優(yōu)先級(jí)與執(zhí)行延遲:

        // 調(diào)用后延遲1秒執(zhí)行,優(yōu)先級(jí)最低
        scheduler.postTask(() => console.log('Hello, postTask'), {
           delay1000,
           priority'background',
        });

        postTask建立在AbortSignal API[3]上,所以我們可以取消尚在排隊(duì)還未執(zhí)行的回調(diào)函數(shù)。

        通過(guò)使用TaskController API控制:

        const controller = new TaskController('background');
        window.addEventListener('beforeunload', () => controller.abort());
         
        scheduler.postTask(() => console.log('Hello, postTask'), {
           signal: controller.signal,
        });

        同時(shí),實(shí)驗(yàn)性的schedule.wait方法可以讓我們輕松的等待某一時(shí)機(jī)后再執(zhí)行任務(wù)。

        比如,我們可以在頁(yè)面加載完成后異步加載xxx.js

        async function loadxxx({
          // 等待事件被派發(fā)
          await scheduler.wait('myPageHasLoaded');
          return import('xxx.js');
        }
         
        // 頁(yè)面加載后派發(fā)事件
        window.dispatchEvent(new CustomEvent('myPageHasLoaded'));

        以上代碼被簡(jiǎn)化為postTaskevent配置項(xiàng):

        scheduler.postTask(() => import('xxx.js'), {
           event'myPageHasLoaded'
        })

        總結(jié)

        「優(yōu)先級(jí)調(diào)度」可以應(yīng)用在很多領(lǐng)域,比如:

        • 資源提前、延后請(qǐng)求

        • 第三方資源延遲加載

        ......

        可以預(yù)見(jiàn),未來(lái)這勢(shì)必會(huì)增加前端編程復(fù)雜度。

        就像曾經(jīng),當(dāng)web應(yīng)用復(fù)雜到一定程度時(shí),出現(xiàn)了前端框架,開(kāi)發(fā)者不用直接操作DOM。

        未來(lái),當(dāng)「優(yōu)先級(jí)調(diào)度」復(fù)雜到一定程度時(shí),一定也會(huì)出現(xiàn)集成解決方案,讓開(kāi)發(fā)者不用直接操作優(yōu)先級(jí)

        慢著,這不就是React現(xiàn)在在做的事么?

        參考資料

        [1]

        Building a Faster Web Experience with the postTask Scheduler: https://medium.com/airbnb-engineering/building-a-faster-web-experience-with-the-posttask-scheduler-276b83454e91

        [2]

        scheduler.postTask: https://github.com/WICG/scheduling-apis/blob/main/explainers/prioritized-post-task.md

        [3]

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

        瀏覽 60
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            无码啪碰色一区 | 丁香五月激情综合在线 | 水蜜桃视频网站在线观看 | 国产精品久久久久久久专区 | 亚洲AV秘 无码一区二区三竹菊 | 国产靠逼片直接看的 | 国产视频18 | 欧妇女乱妇女乱视频 | 老头一级片 | 快穿之h啪肉取液系统姜柔 |