React Fiber中面試官最關(guān)心的技術(shù)話題
引言
關(guān)于 React Fiber 出來(lái)也有幾年了,可最近面試多了才發(fā)現(xiàn),還是有很多人一知半解,所以本文梳理了一下有關(guān) Fiber、以及這個(gè)話題環(huán)環(huán)相扣,可以延伸的點(diǎn),給大家面試復(fù)習(xí)、查缺補(bǔ)漏,如果你是面試官也可直接拿去提問(wèn)
React Fiber
說(shuō)一下 React Fiber
是指時(shí)間分片嘛,可以把渲染工作切片,優(yōu)化渲染性能的。
因?yàn)?nbsp;React
是函數(shù)式編程嘛,單向數(shù)據(jù)流,需要手動(dòng) setState
來(lái)更新,所以當(dāng)數(shù)據(jù)改變時(shí)會(huì)默認(rèn)全部重新渲染整個(gè)組件樹(shù),而構(gòu)建虛擬 DOM
則是采用同步遞歸的方式,如果組件很復(fù)雜且嵌套深,那么這個(gè)構(gòu)建虛擬 DOM
的過(guò)程就需要很多時(shí)間,而這種任務(wù)默認(rèn)要執(zhí)行完才會(huì)把控制權(quán)交給瀏覽器,一旦執(zhí)行時(shí)間很長(zhǎng),可能就會(huì)地把瀏覽器卡死。
雖然可以用 pureComponent
/shouldComponentUpdate
/useMemo
/useCallback
等方法來(lái)進(jìn)行控制部分更新或緩存,但也是治標(biāo)不治本。而 fiber
是可以使渲染過(guò)程被中斷,可以把控制權(quán)先交還給瀏覽器,讓位高優(yōu)先級(jí)的任務(wù),等瀏覽器空閑時(shí)再恢復(fù)渲染,這樣就不會(huì)顯得卡頓,而是一幀一幀有規(guī)律的執(zhí)行任務(wù),看起來(lái)雖然有點(diǎn)慢,但是一直在慢慢執(zhí)行的
就像一個(gè)房子,組件層級(jí)就像房子的樓層,但是每一層房子頂都破了很多個(gè)洞的,那幾個(gè)方法就像一片瓦,都能蓋一個(gè)小洞,但稍不注意少蓋一個(gè)房間就會(huì)漏水,房間里的人(用戶)就能感知到(卡),而 fiber
就像在破洞下面放了根水管直接通到屋外,雖然看起來(lái)水管彎彎繞繞的,水落地的時(shí)間慢了(執(zhí)行時(shí)間長(zhǎng)了),但房間里的人,就感覺(jué)不到漏水了(屋子還是個(gè)破屋子)
實(shí)在是因?yàn)?nbsp;React
沒(méi)辦法在編譯階段優(yōu)化更多了,所以采用這種方式來(lái)彌補(bǔ)傷害
React Fiber 是怎么實(shí)現(xiàn)的
主要是通過(guò)兩個(gè)原生的 API
來(lái)實(shí)現(xiàn)的 requestAnimationFrame
和 requestIdleCallback
顯示器每秒 60
幀我們看著才不會(huì)感覺(jué)到卡嘛,比如動(dòng)畫(huà)的時(shí)候,一幀的時(shí)間內(nèi)布局和繪制結(jié)束,還有剩余時(shí)間,JS
就會(huì)拿到主線程使用權(quán),如果 JS
某個(gè)任務(wù)執(zhí)行過(guò)長(zhǎng),動(dòng)畫(huà)下一幀開(kāi)始時(shí) JS
還沒(méi)有執(zhí)行完,就會(huì)導(dǎo)致掉幀,出現(xiàn)卡頓。
所以就通過(guò)把 JS
任務(wù)分成更小的任務(wù)塊,分到每一幀上的方式,一幀時(shí)間到先暫停 JS
執(zhí)行,然后下一幀繪制任完成再把主線程交給 JS
,在每一幀繪制之前調(diào)用 requestAnimationFrame
;在每一幀空間階段,就是一幀動(dòng)畫(huà)任務(wù)完成,下一幀還沒(méi)到開(kāi)始時(shí)間,這中間還有時(shí)間的話就調(diào)用 requetIdleCallback
,執(zhí)行它里面的任務(wù)
其他方式能實(shí)現(xiàn)
函數(shù)式編程嘛,generator
就可以控制函數(shù)的運(yùn)行過(guò)程中斷和恢復(fù),就像這樣:
// 任務(wù)列表 const tasks = [] function * run () { let task while(task = task.shift()) { // 如果有高優(yōu)先級(jí)的任務(wù) if (hasHighPriorityTask()) { // 中斷 yield } } } // 中斷后恢復(fù) const iterator = run() // 這樣就恢復(fù)了 iterator.next()
為什么不直接用 generator
這個(gè)問(wèn)題 React
開(kāi)發(fā)者有在源碼里回答過(guò):
- 一是因?yàn)?nbsp;
React
是迭代的,而使用generator
+yield
的話需要把所有代碼都包裝成這個(gè)形式,非常麻煩,工作量很大 - 二是
generator
內(nèi)部是有狀態(tài)的,比如一個(gè)函數(shù)里有用到多個(gè)yield
中斷,就像await
一樣,有時(shí)候后面的會(huì)依賴(lài)前面的結(jié)果,可當(dāng)后面的執(zhí)行前,前面的又更新了,后面就無(wú)法拿到最新的值,這樣就不可控了
所以就自己實(shí)現(xiàn)一個(gè)完全可控的
怎么判斷當(dāng)前是否有高優(yōu)先級(jí)的任務(wù)
這個(gè)據(jù)我所知 JS
好像沒(méi)法判斷,而是按幀的時(shí)間,如果一幀內(nèi)任務(wù)還沒(méi)執(zhí)行完,就中斷當(dāng)前任務(wù),把控制權(quán)交給瀏覽器
瀏覽器什么時(shí)候才有空呢
每秒60幀算,每幀就是 1000/60 = 16.7ms
差不多,每幀任務(wù)執(zhí)行完會(huì)調(diào) requetIdleCallback(callback)
,并且在 callback
中會(huì)有一個(gè)參數(shù)告訴我們當(dāng)前幀還有多少時(shí)間給我們執(zhí)行任務(wù)
那瀏覽器一幀內(nèi)要做哪些事情
比如布局(layout
)、繪制(paint
)、JS
的執(zhí)行、處理用戶輸入事件、requestAnimation
調(diào)用等,如果在一幀內(nèi)處理完了這些剩余時(shí)間就用來(lái)執(zhí)行 requetIdleCallback
,直到下一幀開(kāi)始
- 如果瀏覽器很忙,一幀結(jié)束了還沒(méi)執(zhí)行怎么辦
requetIdleCallback(callback, options)
,還有第二個(gè)參數(shù),里面有個(gè) timeout
字段(毫秒),如果超過(guò)這個(gè)時(shí)間還沒(méi)有被執(zhí)行的話,那么下一幀就會(huì)強(qiáng)制執(zhí)行
- 就是說(shuō)超時(shí)后一定會(huì)被執(zhí)行咯
也不一定,React
里有 5
個(gè)優(yōu)先級(jí)的等級(jí),高優(yōu)先級(jí)的會(huì)被優(yōu)先執(zhí)行,低優(yōu)先級(jí)的慢慢等下去,等級(jí)是這樣的
Immediate
: 最高優(yōu)先級(jí),會(huì)馬上執(zhí)行的不能中斷UserBlocking
: 這一般是用戶交互的結(jié)果,需要及時(shí)反饋Normal
: 普通等級(jí)的,比如網(wǎng)絡(luò)請(qǐng)求等不需要用戶立即感受到變化的Low
: 低優(yōu)先級(jí)的,這種任務(wù)可以延后,但最后始終是要執(zhí)行的Idle
: 最低等級(jí)的任務(wù),可以被無(wú)限延遲的,比如console.log()
如果是相同優(yōu)先級(jí)的任務(wù),就會(huì)按推入任務(wù)隊(duì)列的順序來(lái)執(zhí)行
兼容性怎么樣
requetIdleCallback
兼容性是很差的,React
也是通過(guò) messageChannel
模擬實(shí)現(xiàn)的 requetIdleCallback
的功能
除了 MessageChannel 還有沒(méi)有其他類(lèi)似方法
還有一個(gè)功能類(lèi)似的 BroadcastChannel
以上就是React Fiber中面試官最關(guān)心的技術(shù)話題的詳細(xì)內(nèi)容,更多關(guān)于React Fiber面試技術(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Jira 任務(wù)管理系統(tǒng)項(xiàng)目總結(jié)講解
這篇文章主要為大家介紹了Jira 任務(wù)管理系統(tǒng)項(xiàng)目總結(jié)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08React引入css的幾種方式及應(yīng)用小結(jié)
這篇文章主要介紹了React引入css的幾種方式及應(yīng)用小結(jié),操作styled組件的樣式屬性,可在組件標(biāo)簽上定義屬性、也可以通過(guò)attrs定義屬性,本文通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03關(guān)于React Native報(bào)Cannot initialize a parameter of type''NSArra
這篇文章主要介紹了關(guān)于React Native報(bào)Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>錯(cuò)誤,本文給大家分享解決方案,需要的朋友可以參考下2021-05-05詳細(xì)談?wù)凴eact中setState是一個(gè)宏任務(wù)還是微任務(wù)
學(xué)過(guò)react的人都知道,setState在react里是一個(gè)很重要的方法,使用它可以更新我們數(shù)據(jù)的狀態(tài),下面這篇文章主要給大家介紹了關(guān)于React中setState是一個(gè)宏任務(wù)還是微任務(wù)的相關(guān)資料,需要的朋友可以參考下2021-09-09react-native ListView下拉刷新上拉加載實(shí)現(xiàn)代碼
本篇文章主要介紹了react-native ListView下拉刷新上拉加載實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08