React之Fiber
React Fiber
是對核心演算法的一次重新實現。 React Fiber
把更新過程碎片化,把一個耗時長的任務分成很多小片,每一個小片的執行時間很短,雖然總時間依然很長,但是在每個小片執行完之後,都給其他任務一個執行的機會,這樣唯一的執行緒就不會被獨佔,其他任務依然有執行的機會
- 在
React Fiber
中,一次更新過程會分成多個分片完成,所以完全有可能一個更新任務還沒有完成,就被另一個更高優先順序的更新過程打斷,這時候,優先順序高的更新任務會優先處理完,而低優先順序更新任務所做的工作則會完全作廢,然後等待機會重頭再來 - 因為一個更新過程可能被打斷,所以
React Fiber
一個更新過程被分為兩個階段(Phase
):第一個階段Reconciliation Phase
和第二階段Commit Phase
- 在第一階段
Reconciliation Phase
,React Fiber
會找出需要更新哪些DOM
,這個階段是可以被打斷的;但是到了第二階段Commit Phase
,那就一鼓作氣把DOM
更新完,絕不會被打斷 - 這兩個階段大部分工作都是
React Fiber
做,和我們相關的也就是生命週期函式
React Fiber
改變了之前 react
的元件渲染機制,新的架構使原來同步渲染的元件現在可以非同步化,可中途中斷渲染,執行更高優先順序的任務。釋放瀏覽器主執行緒
關鍵特性
- 增量渲染(把渲染任務拆分成塊,勻到多幀)
- 更新時能夠暫停,終止,複用渲染任務
- 給不同型別的更新賦予優先順序
- 併發方面新的基礎能力
增量渲染用來解決掉幀的問題,渲染任務拆分之後,每次只做一小段,做完一段就把時間控制權交還給主執行緒,而不像之前長時間佔用
二、元件的渲染順序
假如有A,B,C,D元件,層級結構為:
我們知道元件的生命週期為:
掛載階段:
constructor() componentWillMount() render() componentDidMount()
更新階段為:
componentWillReceiveProps() shouldComponentUpdate() componentWillUpdate() render() componentDidUpdate
那麼在掛載階段, A,B,C,D
的生命週期渲染順序是如何的呢?
那麼在掛載階段,A,B,C,D的生命週期渲染順序是如何的呢?
以 render()
函式為分界線。從頂層元件開始,一直往下,直至最底層子元件。然後再往上
元件 update
階段同理
前面是 react16
以前的組建渲染方式。這就存在一個問題
如果這是一個很大,層級很深的元件, react
渲染它需要幾十甚至幾百毫秒,在這期間, react
會一直佔用瀏覽器主執行緒,任何其他的操作(包括使用者的點選,滑鼠移動等操作)都無法執行
Fiber架構就是為了解決這個問題
看一下fiber架構 組建的渲染順序
加入 fiber
的 react
將元件更新分為兩個時期
這兩個時期以render為分界
-
render
前的生命週期為phase1
, -
render
後的生命週期為phase2
-
phase1
的生命週期是可以被打斷的,每隔一段時間它會跳出當前渲染程序,去確定是否有其他更重要的任務。此過程,React
在workingProgressTree
(並不是真實的virtualDomTree
)上覆用current
上的Fiber
資料結構來一步地(通過requestIdleCallback
)來構建新的 tree,標記處需要更新的節點,放入佇列中 -
phase2
的生命週期是不可被打斷的,React
將其所有的變更一次性更新到DOM
上
這裡最重要的是phase1這是時期所做的事。因此我們需要具體瞭解phase1的機制
- 如果不被打斷,那麼
phase1
執行完會直接進入render
函式,構建真實的virtualDomTree
- 如果元件再
phase1
過程中被打斷,即當前元件只渲染到一半(也許是在willMount
,也許是willUpdate
~反正是在render之前的生命週期),那麼react
會怎麼幹呢?react
會放棄當前元件所有幹到一半的事情,去做更高優先順序更重要的任務(當然,也可能是使用者滑鼠移動,或者其他react監聽之外的任務),當所有高優先順序任務執行完之後,react
通過callback
回到之前渲染到一半的元件,從頭開始渲染。(看起來放棄已經渲染完的生命週期,會有點不合理,反而會增加渲染時長,但是react
確實是這麼幹的)
所有phase1的生命週期函式都可能被執行多次,因為可能會被打斷重來
這樣的話,就和 react16
版本之前有很大區別了,因為可能會被執行多次,那麼我們最好就得保證 phase1
的生命週期每一次執行的結果都是一樣的,否則就會有問題,因此,最好都是純函式
- 如果高優先順序的任務一直存在,那麼低優先順序的任務則永遠無法進行,元件永遠無法繼續渲染。這個問題facebook目前好像還沒解決
- 所以,facebook在
react16
增加fiber
結構,其實並不是為了減少元件的渲染時間,事實上也並不會減少,最重要的是現在可以使得一些更高優先順序的任務,如使用者的操作能夠優先執行,提高使用者的體驗,至少使用者不會感覺到卡頓