<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          揭秘: 一個 JavaScript 庫如何帶動 Chromium 的發(fā)展?

          共 3118字,需瀏覽 7分鐘

           ·

          2021-02-02 10:29

          想要提高一個網(wǎng)頁的加載速度是非常困難的,如果你的網(wǎng)站是在使用 JavaScript 渲染的內(nèi)容,你必須要在網(wǎng)頁的加載速度和網(wǎng)頁的輸入響應(yīng)能力之間作出權(quán)衡:

          • 一次性執(zhí)行首屏需要執(zhí)行的邏輯(負(fù)載性能好,輸入響應(yīng)能力差)
          • 將復(fù)雜的邏輯拆分成更小塊的任務(wù)執(zhí)行,以保證對外界輸入的響應(yīng)(負(fù)載性能差,輸入響應(yīng)能力好)

          為了避免這種取舍,FacebookChromium 中提出并實(shí)現(xiàn)了 isInputPending() API,它可以提高網(wǎng)頁的響應(yīng)能力,但是不會對性能造成太大影響。

          目前 isInputPending API 僅在 Chromium 的 87 版本開始提供,其他瀏覽器并未實(shí)現(xiàn)。

          背景

          在現(xiàn)今的 JavaScript 生態(tài)中,大多數(shù)工作都是在一個線程完成的:主線程。這種設(shè)計為開發(fā)者提供了一個健壯的執(zhí)行模型,但是如果腳本執(zhí)行的時間太長,則用戶體驗(yàn)(尤其是響應(yīng)能力)可能會遭受嚴(yán)重?fù)p失。例如,用戶正在輸入一些內(nèi)容時, JavaScript 正在執(zhí)行大量的邏輯,則在這些邏輯完成之前,瀏覽器都不能處理用戶的輸入事件。

          現(xiàn)在的最佳實(shí)踐是通過將復(fù)雜的邏輯拆分成更小塊的任務(wù)執(zhí)行來解決這種問題。在頁面加載期間,頁面可以運(yùn)行一些 JavaScript 邏輯,然后將控制權(quán)轉(zhuǎn)交給瀏覽器,這時瀏覽器可以檢測自己的事件隊列,看看是不是需要響應(yīng)用戶輸入,然后再繼續(xù)運(yùn)行 JavaScript ,這種方式雖然會有一些幫助,但是同時也可能會帶來其他問題。

          每次頁面將控制權(quán)交還給瀏覽器時,瀏覽器都會花費(fèi)一些時間來檢查它的事件隊列,處理完事件后再獲取下一個 JavaScript 代碼邏輯。當(dāng)瀏覽器更快地響應(yīng)事件時,頁面的整體加載時間會變慢。而且,用戶輸交互比較多的情況下,頁面加載會非常慢。如果我們不那么頻繁地進(jìn)行上面的過程,那么瀏覽器響應(yīng)用戶事件所花費(fèi)的時間就會更長。

          Facebook 提出的 isInputPending API 是第一個將中斷的概念用于瀏覽器用戶交互的的功能,并且允許 JavaScript 能夠檢查事件隊列而不會將控制權(quán)交于瀏覽器。

          下面我們來具體看一個例子。

          一個例子

          假設(shè)您需要做很多顯示阻塞的工作來加載頁面,例如,從組件生成標(biāo)記,分解質(zhì)數(shù)或僅繪制一個很酷的加載微調(diào)器。這些中的每一個都分解為一個離散的工作項(xiàng)。使用調(diào)度程序模式,讓我們勾勒出如何在假設(shè)的processWorkQueue()函數(shù)中處理我們的工作:

          假設(shè)你再首屏加載頁面時要處理非常多的阻塞邏輯,例如從組件生成標(biāo)記,分解質(zhì)數(shù),或者只是繪制一個很酷的加載器動畫。這些邏輯都會被分解成一個獨(dú)立的工作項(xiàng)。使用 scheduler 模式,讓我們在一個假設(shè)的 processWorkQueue() 函數(shù)中處理我們的邏輯:

          const?DEADLINE?=?performance.now()?+?QUANTUM;
          while?(workQueue.length?>?0)?{
          ??if?(performance.now()?>=?DEADLINE)?{
          ????//?Yield?the?event?loop?if?we're?out?of?time.
          ????setTimeout(processWorkQueue);
          ????return;
          ??}
          ??let?job?=?workQueue.shift();
          ??job.execute();
          }

          通過 processWorkQueue() 延時鏈?zhǔn)秸{(diào)用 setTimeout(),我們使瀏覽器能夠在某種程度上保持對輸入的響應(yīng),同時仍然在相對不間斷地運(yùn)行。但是,可能需要很長時間才能完成其他需要控制事件循環(huán)的工作,或者使 QUANTUM 事件延遲增加一毫秒。

          在RAIL模型下,QUANTUM 一個好的值是<50ms,這取決于要完成的工作類型。該值主要決定了處理能力和延遲之間的平衡。

          但是,我們還可以做的更好:

          const?DEADLINE?=?performance.now()?+?QUANTUM;
          while?(workQueue.length?>?0)?{
          ??if?(navigator.scheduling.isInputPending()?||?performance.now()?>=?DEADLINE)?{
          ????//?Yield?if?we?have?to?handle?an?input?event,?or?we're?out?of?time.
          ????setTimeout(processWorkQueue);
          ????return;
          ??}
          ??let?job?=?workQueue.shift();
          ??job.execute();
          }

          通過調(diào)用 navigator.scheduling.isInputPending(),我們可以更快地響應(yīng)輸入,同時仍然確保我們的阻塞邏輯能夠不間斷地執(zhí)行。如果在完成這些邏輯之前對用戶交互(例如繪畫)以外的其他操作不感興趣,則可以方便地增加輸入的長度 QUANTUM。

          默認(rèn)情況下,“連續(xù)”的事件類型不會返回 isInputPending(),比如 mousemove,pointermove 等等。如果你對這些也感興趣的話,沒問題??梢酝ㄟ^為 isInputPending() 提供一個包含連續(xù)變量為true的字典:

          const?DEADLINE?=?performance.now()?+?QUANTUM;
          const?options?=?{?includeContinuous:?true?};
          while?(workQueue.length?>?0)?{
          ??if?(navigator.scheduling.isInputPending(options)?||?performance.now()?>=?DEADLINE)?{
          ????//?Yield?if?we?have?to?handle?an?input?event?(any?of?them!),?or?we're?out?of?time.
          ????setTimeout(processWorkQueue);
          ????return;
          ??}
          ??let?job?=?workQueue.shift();
          ??job.execute();
          }

          React 這樣的框架正在將 isInputPending() 使用類似的邏輯構(gòu)建到其核心調(diào)度庫中。希望這將使使用這些框架的開發(fā)人員能夠從幕后的 isInputPending() 中受益,而不要進(jìn)行重大的重寫。

          React Fiber

          讓我們回想下 React Fiber 中的時間分片:

          把一個耗時長的任務(wù)分成很多小片,每一個小片的運(yùn)行時間很短,雖然總時間依然很長,但是在每個小片執(zhí)行完之后,都給其他任務(wù)一個執(zhí)行的機(jī)會,這樣唯一的線程就不會被獨(dú)占,其他任務(wù)依然有運(yùn)行的機(jī)會。

          React Fiber 把更新過程碎片化,執(zhí)行過程如下面的圖所示,每執(zhí)行完一段更新過程,就把控制權(quán)交還給 React 負(fù)責(zé)任務(wù)協(xié)調(diào)的模塊,看看有沒有其他緊急任務(wù)要做,如果沒有就繼續(xù)去更新,如果有緊急任務(wù),那就去做緊急任務(wù)。

          如果你對該庫感興趣,可以到 https://github.com/WICG/is-input-pending 參與反饋和討論。

          參考:https://web.dev/isinputpending/

          不得不說 React 團(tuán)隊還是非常強(qiáng)的,一個 JavaScript 庫能帶動瀏覽器的發(fā)展。雖然這還是第一個由 Facebook 貢獻(xiàn)給瀏覽器的能力,不過未來可期,讓我們期待更多更強(qiáng)大的 API 吧!

          你的點(diǎn)贊和在看是對我最大的支持 ??

          瀏覽 51
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性69| 狠狠V欧美V日韩V亚洲Ⅴ | 啊啊啊啊被操逼了好爽视频免费 | 成人超碰福利 | 国产一级女婬乱免费看 |