瞧一瞧React Fiber

陌上兮月發表於2021-02-18

啥是React Fiber?

React Fiber,簡單來說就是一個從React v16開始引入的新協調引擎,用來實現Virtual DOM的增量渲染。

說人話:就是一種能讓React檢視更新過程變得更加流暢順滑的處理手法。

我們都知道:程式大,執行緒小。而Fiber(纖維)是一種比執行緒還要細粒度的處理機制。從這個單詞也可以猜測:React Fiber會很“細”。到底怎麼個細法,我們接著往下看。

為什麼會有React Fiber?

之前說了,React Fiber是為了讓React的檢視更新過程變得更加流暢順滑。怎麼,之前React的檢視更新不流暢,不順滑了?

還真是的,在React v16之前,React的檢視更新確實存在很大的效能問題,其中首當其衝的,就是它的同步更新機制

在React決定要載入或更新一顆元件樹之前,會大致做出如下一系列動作:呼叫各元件的生命週期函式 --> 計算和對比Virtual DOM --> 更新真實的DOM樹。這個過程是同步的,也就是說,一旦這個過程開始,它就會一鼓作氣跑完,一直到真實DOM樹更新完畢。

然而,當元件樹比較龐大時,這種機制的問題就來了:一顆擁有300個元件的元件樹需要全部更新,假設一個元件更新只需耗時1ms,整棵樹更新一次就需要耗時300ms。在這300ms期間,瀏覽器的主執行緒一直在“專心致志”地忙著更新這顆元件樹(這時函式的呼叫棧會非常長),對於頁面上的任何操作都是“不聞不問”的。在這期間,假如使用者在一個輸入框敲了幾個字,頁面上也不會有任何反應,因為渲染按鍵輸入結果也需要主執行緒來做,然而此時主執行緒正忙著更新元件樹呢。等到300ms結束了,瀏覽器主執行緒有空了,才把剛剛敲的那幾個字渲染到input輸入框內。

太卡了,真的。

由於JavaScript的單執行緒工作特點,業內一直有個這樣的原則:**任何動作都不要長時間霸佔主執行緒,如果遲遲不歸還主執行緒,那麼在這期間程式就沒法對其他輸入作出響應。使用者輸入了卻沒有響應,或者說響應來的很慢,也就是我們常常說的“卡頓”。顯然,React的同步更新機制在元件樹龐大時就違反了這一原則,犯了大忌。

這就是React Fiber出現的原因:為了解決舊版React檢視更新的效能瓶頸

React Fiber到底怎麼工作的?

首先,React Fiber並沒有解決更新龐大元件樹耗時長的問題,實際上總的耗時還是一樣的長。但是它解決了一個被廣大開發者口誅筆伐的惡行:長時間霸佔主執行緒不放。

而它解決的方法就是:分片。

它的工作原理是這樣的:把耗時長的更新任務拆解成一個個小的任務分片,每執行完一個小的任務分片,都歸還一次主執行緒,看看有沒有什麼其他緊急任務要做。如果在歸還主執行緒時恰巧發現有緊急任務,那麼會馬上停掉當前更新任務,轉而讓主執行緒去做緊急任務,等主執行緒做完緊急任務,再重新做更新任務。(注意⚠️:是重新!不是從上次被打斷的點繼續);如果沒有緊急任務,才敢唯唯諾諾地繼續做接下來的任務分片。

簡單來說,就是降了檢視更新的優先順序,把更新過程碎片化。

現在我們捋一捋,React Fiber會這樣處理一個更新過程:

  1. 將一個更新過程分為Reconciliation階段和Commit階段;
  2. 對於Reconciliation階段進行分片處理,這個階段可以被更緊急的任務打斷,分片任務做到一半可能要重來;
  3. 對於Commit階段,直接一鼓作氣把DOM更新完,不能被打斷。

React Fiber對我們日常開發有什麼影響?

React Fiber在Reconciliation階段可能會呼叫以下生命週期函式(這也意味著在這個階段的生命週期函式在一次載入和更新過程中可能會被多次呼叫):

  • componentWillMount
  • componentWillUpdate
  • componentWillReceiveProps
  • shouldComponentUpdate

如果你恰巧沒有上react hooks的車,而是使用傳統的類元件進行開發,那麼切記,不要在以上幾個生命週期函式中做只需要做一次的操作(比如:頁面初始化時發起一個ajax請求獲取資料)。

如果你平常使用react hooks進行開發,那沒事了,就當看了個熱鬧。

相關文章