溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

React17啟發(fā)式更新算法是什么

發(fā)布時間:2022-02-25 10:01:46 來源:億速云 閱讀:109 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“React17啟發(fā)式更新算法是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“React17啟發(fā)式更新算法是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

為什么會出現(xiàn)啟發(fā)式更新算法

框架的運行性能是框架設(shè)計者在設(shè)計框架時需要重點關(guān)注的點。

Vue使用模版語法,可以在編譯時對確定的模版作出優(yōu)化。

ReactJS寫法太過靈活,使他在編譯時優(yōu)化方面先天不足。

所以,React的優(yōu)化主要在運行時。

React15的痛點

在運行時優(yōu)化方面,React一直在努力。

比如,React15實現(xiàn)了batchedUpdates(批量更新)。

即同一事件回調(diào)函數(shù)上下文中的多次setState只會觸發(fā)一次更新。

但是,如果單次更新就很耗時,頁面還是會卡頓(這在一個維護(hù)時間很長的大應(yīng)用中是很常見的)。

這是因為React15的更新流程是同步執(zhí)行的,一旦開始更新直到頁面渲染前都不能中斷。

為了解決同步更新長時間占用線程導(dǎo)致頁面卡頓的問題,也為了探索運行時優(yōu)化的更多可能,React開始重構(gòu)并一直持續(xù)至今。

重構(gòu)的目標(biāo)是實現(xiàn)Concurrent Mode(并發(fā)模式)。

(推薦教程:React教程)

Concurrent Mode

Concurrent Mode的目的是實現(xiàn)一套可中斷/恢復(fù)的更新機制。

其由兩部分組成:

  • 一套協(xié)程架構(gòu)

  • 基于協(xié)程架構(gòu)的啟發(fā)式更新算法

其中,協(xié)程架構(gòu)就是React16中實現(xiàn)的Fiber Reconciler。

我們可以將Fiber Reconciler理解為React自己實現(xiàn)的Generator

Fiber Reconciler從理念到源碼的詳細(xì)介紹見這里

協(xié)程架構(gòu)使更新可以在需要的時機被中斷,這樣瀏覽器就有時間完成樣式布局與樣式繪制,減少卡頓(掉幀)的出現(xiàn)。

當(dāng)瀏覽器進(jìn)入下一次事件循環(huán),協(xié)程架構(gòu)可以恢復(fù)中斷或者拋棄之前的更新,重新開始新的更新流程。

啟發(fā)式更新算法就是控制協(xié)程架構(gòu)工作方式的算法。

React16的啟發(fā)式更新算法

啟發(fā)式更新算法的啟發(fā)式指什么呢?

啟發(fā)式指不通過顯式的指派,而是通過優(yōu)先級調(diào)度更新。

其中優(yōu)先級來源于人機交互的研究成果。

比如:

人機交互的研究成果表明:

  • 當(dāng)用戶在輸入框輸入內(nèi)容時,希望輸入的內(nèi)容能實時響應(yīng)在輸入框

  • 當(dāng)異步請求數(shù)據(jù)后,即使等待一會兒再顯示內(nèi)容,用戶也是可以接受的

基于此,在React16中

輸入框輸入內(nèi)容觸發(fā)的更新優(yōu)先級 > 請求數(shù)據(jù)返回后觸發(fā)更新優(yōu)先級

算法實現(xiàn) 在React16、17中,在組件內(nèi)執(zhí)行this.setState后會在該組件對應(yīng)的fiber節(jié)點內(nèi)產(chǎn)生一種鏈表數(shù)據(jù)結(jié)構(gòu)update。

其中,update.expirationTimes為類似時間戳的字段,表示優(yōu)先級。

expirationTimes從字面意義理解為過期時間。

該值離當(dāng)前時間越接近,該update 優(yōu)先級越高。

當(dāng)update.expirationTimes超過當(dāng)前時間,則代表該update過期,優(yōu)先級變?yōu)樽罡撸赐剑?/p>

一棵fiber樹的多個fiber節(jié)點可能存在多個update。

每次Fiber Reconciler調(diào)度更新時,會在所有fiber節(jié)點的所有update.expirationTimes中選擇一個expirationTimes(一般選擇最大的),作為本次更新的優(yōu)先級。

并從根fiber節(jié)點開始向下構(gòu)建新的fiber樹。

構(gòu)建過程中如果某個fiber節(jié)點包含update,且

update.expirationTimes >= expirationTimes

則該update對應(yīng)的state變化會體現(xiàn)在本次更新中。

可以理解為:每次更新,都會選定一個優(yōu)先級(expirationTimes),最終頁面會渲染為該優(yōu)先級對應(yīng)update的快照。

算法缺陷

如果只考慮中斷/繼續(xù)這樣的 CPU 操作,以expirationTimes大小作為衡量優(yōu)先級依據(jù)的模型可以很好工作。

但是expirationTimes模型不能滿足 IO 操作(Suspense)。

在該模型下,高優(yōu)先級 IO 任務(wù)(Suspense)會中斷低優(yōu)先級 CPU 任務(wù)。

還記得么,每次更新,都是以某一優(yōu)先級作為整棵樹的優(yōu)先級更新標(biāo)準(zhǔn),而不僅僅是某一組件,即使更新的源頭(update)確實是某個組件產(chǎn)生的。

expirationTimes模型只能區(qū)分是否>=expirationTimes這種情況。

為了拓展Concurrent Mode能力邊界,需要一種更細(xì)粒度的啟發(fā)式優(yōu)先級更新算法。

(推薦教程:React入門實例教程)

React17啟發(fā)式更新算法

最理想的模型是:可以指定任意幾個優(yōu)先級,更新會以這些優(yōu)先級對應(yīng)update生成頁面快照。

但是現(xiàn)有架構(gòu)下,該方案實現(xiàn)上有瓶頸。

妥協(xié)之下,React17的解決方案是:指定一個連續(xù)的優(yōu)先級區(qū)間,每次更新都會以區(qū)間內(nèi)包含的優(yōu)先級生成對應(yīng)頁面快照。

這種優(yōu)先級區(qū)間模型被稱為lanes(車道模型)。

具體做法是:使用一個31位的二進(jìn)制代表31種可能性。

  • 其中每個bit被稱為一個lane(車道),代表優(yōu)先級

  • 某幾個lane組成的二進(jìn)制數(shù)被稱為一個lanes,代表一批優(yōu)先級

可以從源碼中看到,從藍(lán)線一路劃下去,每個bit都對應(yīng)一個lanelanes

當(dāng)update產(chǎn)生,會根據(jù)React16同樣的啟發(fā)式方式,獲得如下優(yōu)先級的一種:

export const SyncLanePriority: LanePriority = 17; export const SyncBatchedLanePriority: LanePriority = 16; export const InputDiscreteLanePriority: LanePriority = 14; export const InputContinuousLanePriority: LanePriority = 12; export const DefaultLanePriority: LanePriority = 10; export const TransitionShortLanePriority: LanePriority = 8; export const TransitionLongLanePriority: LanePriority = 6;

其中值越高,優(yōu)先級越大。

比如:

  • 點擊事件回調(diào)中觸發(fā)this.setState產(chǎn)生的update會獲得InputDiscreteLanePriority。

  • 同步的update會獲得SyncLanePriority。

接下來,update會以priority為線索尋找沒被占用的lane。

如果當(dāng)前fiber樹已經(jīng)存在更新且更新的lanes包含了該lane,則update需要尋找其他lane

比如,InputDiscreteLanePriority對應(yīng)的lanesInputDiscreteLanes

// 第4、5位為1 const InputDiscreteLanes: Lanes = 0b0000000000000000000000000011000;

lanes包含第4、5位 2 個 bit位。

如果其中

// 第五位為1 0b0000000000000000000000000010000

第五位的lane已經(jīng)被占用,則該update可以嘗試占有后一個,即

// 第四位為1 0b0000000000000000000000000001000

如果InputDiscreteLanes的兩個lane都被占用,則該update的優(yōu)先級會下降到InputContinuousLanePriority并繼續(xù)尋找空余的lane。

這個過程就像:購物中心每一層(不同優(yōu)先級)都有一個露天停車場(lanes),停車場有多個車位(lane)。

我們先開車到頂樓找車位(lane),如果沒有車位就下一樓繼續(xù)找。

直到找到空余車位。

由于lanes可以包含多個lane,可以很方便的區(qū)分 IO 操作(Suspense)與 CPU 操作。

當(dāng)構(gòu)建fiber樹進(jìn)入構(gòu)建Suspense子樹時,會將Suspenselane插入本次更新選定的lanes中。

當(dāng)構(gòu)建離開Suspense子樹時,會將Suspense lane從本次更新的lanes中移除。

讀到這里,這篇“React17啟發(fā)式更新算法是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI