React系列——React Fiber 架構介紹資料彙總(翻譯+中文資料)

原文

react-fiber-architecturejavascript

介紹



React Fibre是React核心算法正在進行的從新實現。它是React團隊兩年多的研究成果。

React Fiber的目標是提升其對動畫,佈局和手勢等領域的適用性。它的主體特徵是增量渲染:可以將渲染工做分割成塊,並將其分散到多個幀中。html

其餘主要功能包括在進行更新時暫停,停止或從新使用工做的能力;爲不一樣類型的更新分配優先權的能力;和新的併發原語。java

關於這個文檔

Fiber引入了幾個新穎的概念,很難經過查看代碼來完成。這個文檔是咱們在React項目中隨着Fibre實現的一系列筆記開始的。隨着它的發展,我意識到它也可能成爲其餘人的有用資源。react

我會嘗試儘量使用最普通的語言,並經過明肯定義關鍵術語來避免行話。在可能的狀況下,我也會大量鏈接外部資源。 git

請注意,我不在React團隊,也不會從任何權威機構發言。這不是一個正式的文件。我已經要求React團隊的成員對其進行檢查以確保準確性。 程序員

這也是一個正在進行的工做。Fiber是一個正在進行的項目,在完成以前可能會經歷重大的重構。我也試圖在這裏記錄它的設計。改進和建議是很是受歡迎的。 github

個人目標是在閱讀本文檔以後,您將會理解Fiber的實施狀況,並最終甚至可以回饋給React。算法

先決條件

我強烈建議您在繼續以前熟悉如下資源: c#

React Components, Elements, and Instances - 「 Component」一般是一個重載的術語。緊緊掌握這些術語相當重要。 瀏覽器

Reconciliation - 對React reconciliation算法的高級描述。

React基本理論概念 - 對React概念模型的描述。其中一些內容在第一次閱讀時可能沒有意義。不要緊,隨着時間的推移會更有意義。

React設計原則 - 特別注意scheduling部分。它很好的解釋了React Fiber的工做原理。

Review

若是你尚未看先決條件,請先看完它。

在咱們深刻研究新的東西以前,讓咱們回顧一下幾個概念。

什麼是reconciliation

reconciliation

React算法,用來比較2顆樹,以肯定哪些部分須要改變。

更新

用於呈現React應用的數據更改。一般是`setState`的結果。最終致使從新渲染。

React的API的核心思想認爲更新會致使整個應用程序從新渲染。這容許開發人員以聲明的方式進行推理,而不用擔憂如何有效地將應用程序從任何特定狀態轉換到另外一個狀態(從A到B,從B到C,從C到A等等)。

實際上,在每次更改時從新渲染整個應用程序只適用於最瑣碎的應用程序;在實際的應用程序中,性能方面的代價很是高昂。 React具備優化功能,可在保持良好性能的同時建立整個應用程序須要從新呈現的外觀。這些優化的大部份內容是reconciliation的一部分。

Reconciliation是被廣泛理解爲「虛擬DOM」的算法。高級描述以下所示:當您渲染React應用程序時,會生成一個描述應用程序的節點樹並保存在內存中。而後將該樹刷新到渲染環境 - 例如,在瀏覽器中,將其轉換爲一組DOM操做。當應用程序更新(一般經過setState),生成一個新的樹。新樹與前一棵樹有區別,以計算須要更新呈現的應用程序的操做。

儘管Fibre是對reconciler的徹頭徹尾的重寫,但React文檔中描述的高級算法在很大程度上是相同的。關鍵是:

  • 假定不一樣的組件類型產生實質上不一樣的樹。React不會試圖區分它們,而是徹底替換舊的樹。
  • 列表的區分使用keys來執行。關鍵應該是「穩定,可預測,獨特」。

Reconciliation與渲染

DOM只是React能夠渲染的渲染環境之一,還能夠經過React Native進行本地iOS和Android視圖。 (這就是爲何「虛擬DOM」有點用詞不當)。

它能夠支持如此多目標是由於React的設計使reconciliation和渲染是分開的階段。reconciler完成了計算樹的哪些部分已經改變的工做;渲染器而後使用該信息實際更新呈現的應用程序。

這種分離意味着React DOM和React Native可使用他們本身的渲染器,同時共享由React核心提供的相同的reconciler。

Fiber從新實現了reconciler。雖然渲染者須要改變以支持(並利用)新的架構,但它並不主要關心渲染。

Scheduling

scheduling

肯定什麼時候應該進行工做的過程。

工做

任何須須執行的計算。工做一般是更新的結果(例如setState)。

React的設計原則文檔在這個主題上很是好,我只是在這裏引用它:

在當前實現中,React遞歸地遍歷樹,並在單個tick中調用整個更新樹的render函數。可是,未來可能會延遲一些更新以免丟幀。

這是React設計中的一個常見主題。當新數據可用時,一些流行的庫實現了「push」方法,其中計算被執行。然而,React堅持「pull」的方法,計算能夠延遲到必要的時候。

React不是一個通用的數據處理庫。這是一個創建用戶界面的庫。咱們認爲它是惟必定位在一個應用程序來知道如今哪些計算是相關的,哪些不是。

若是有什麼東西在屏幕外,咱們能夠推遲任何與之相關的邏輯。若是數據比幀速率更快到達,咱們能夠合併批量更新。咱們能夠優先考慮來自用戶交互的工做(好比點擊按鈕形成的動畫)而不是重要的後臺工做(好比剛剛從網絡加載的新內容),以免丟失幀。

關鍵是:

  • 在用戶界面中,沒有必要當即應用每一個更新。實際上,這樣作可能會形成浪費,致使幀丟失並下降用戶體驗。
  • 不一樣類型的更新具備不一樣的優先級 - 動畫更新須要比從數據存儲更新更快地完成。
  • 基於push的方法要求應用程序(您,程序員)決定如何安排工做。基於pull的方法可使框架(React)更加智能,併爲您作出決定。

目前,React並無以重要的方式利用scheduling;整個子樹的更新結果當即被從新渲染。檢修React的核心算法以利用scheduling是Fiber背後的驅動理念。


如今咱們已經準備好進入Fiber的實施。接下來的部分比咱們迄今爲止所討論的更具技術性。在繼續以前,請確保您對前面的內容感到滿意。

什麼是fiber?

咱們即將討論React Fiber架構的核心。Fiber比應用程序開發人員一般所想的要底層抽象得多。若是你對本身的理解感到沮喪,不要感到氣餒。繼續嘗試,最終會有意義的。 (當你最終獲得它,請建議如何改善這一部分。)

開始了!


咱們已經肯定,Fiber的主要目標是使React可以利用scheduling。具體來講,咱們須要可以

  • 暫停工做,稍後再回來。
  • 爲不一樣類型的工做分配優先權。
  • 重複之前完成的工做。
  • 若是再也不須要,請停止工做。

爲了作到這一點,咱們首先須要一種把工做分解成單元的方法。從某種意義上說,這就是fiber。fiber表明一個工做單元。

爲了更進一步,讓咱們回到React組件做爲數據函數的概念,一般表達爲

v = f(d)

所以渲染一個React應用程序相似於調用其主體包含對其餘函數的調用的函數,等等。這個比喻在思考fiber時頗有用。

計算機一般跟蹤程序執行的方式是使用調用堆棧。當一個函數被執行時,一個新的堆棧框架被添加到堆棧中。該堆棧框表示由該函數執行的工做。

在處理UI時,問題是若是一次執行了太多的工做,它可能會致使動畫丟幀,看起來不穩定。更重要的是,若是某些工做被更新的更新所取代,那麼這些工做多是沒必要要的。這是UI組件和函數之間的比較失敗的地方,由於組件比通常的函數具備更多特定的問題。

較新的瀏覽器(和React Native)實現了API來幫助解決這個確切的問題:requestIdleCallback schedules在空閒期間被調用的低優先級函數,requestAnimationFrame schedules在下一個動畫幀上被調用的高優先級函數。問題是,爲了使用這些API,您須要一種方法來將渲染工做分解爲增量單元。若是隻依賴調用堆棧,它將繼續工做,直到堆棧爲空。

若是咱們能夠自定義調用堆棧的行爲來優化呈現UI,這不是很好嗎?若是咱們能夠隨意中斷調用堆棧並手動操做堆棧幀,這不是很好嗎?

這就是React Fiber的目的。Fiber從新實現堆棧,專門用於React組件。您能夠將單個fiber視爲虛擬堆棧幀。

從新實現堆棧的好處是你能夠將堆棧幀保存在內存中,而後執行它們(不管什麼時候)。這對於完成咱們安排的目標相當重要。

除了調度scheduling,還有手動處理堆棧幀解鎖了諸如併發和錯誤邊界之類的功能的潛力。咱們將在之後的章節中介紹這些話題。

在下一節中,咱們將更多地關注fiber的結構。

fiber的結構

注意:隨着咱們對實現細節的更具體的瞭解,事情可能發生變化的可能性會增長。若是您發現任何錯誤或過期的信息,請提交PR。

具體而言,fiber是一個JavaScript對象,包含有關組件,其輸入和輸出的信息。

fiber對應於堆棧幀,但也對應於組件的一個實例。

這是一些屬於fiber的重要領域。 (這個清單並不詳盡。)

type and key

fiber的type和key與React元素的做用相同。 (實際上,當從一個元素建立一個fiber時,這兩個字段直接被複制過來。)

fiber的type描述了它對應的組件。對於複合組件,類型是函數或類組件自己。對於host組件(div,span等),類型是一個字符串。

從概念上講,type是函數(如在v = f(d)中),其執行被棧幀跟蹤。

隨着type的不一樣,在reconciliation期間使用key來肯定fiber是否能夠從新使用。

child and sibling

這些字段指向其餘fiber,描述fiber的遞歸樹狀結構。

子fiber對應於組件渲染方法返回的值。因此在下面的例子中

function Parent() {
  return <Child />
}

Parent的child fiber對應於Child。

兄弟領域說明了渲染返回多個children的狀況(Fiber中的一個新特性):

function Parent() {
  return [<Child1 />, <Child2 />]
}

child的fiber造成一個單一的鏈表,head是第一個child。因此在這個例子中,Parent的child是Child1,而Child1的兄弟是Child2。

回到咱們的功能比喻,你能夠把一個子fiber想象成一個尾調用函數

return

return fiber是程序在處理完當前fiber後返回的fiber。它在概念上與堆棧幀的返回地址相同。它也能夠被認爲是parent fiber。

若是fiber具備多個子fiber,則每一個子fiber的return fiber是parent。因此在前面的例子中,Child1和Child2的return fiber是Parent。

pendingProps 和 memoizedProps

從概念上講,props是一個函數的arguments。一個fiber的pendingProps在執行開始時被設置,memoizedProps被設置在最後。

當傳入的pendingProps等於memoizedProps時,它代表fiber的先前輸出能夠被重複使用,避免沒必要要的工做。

pendingWorkPriority

一個數字,表示fiber所表明的工做的優先級。 ReactPriorityLevel模塊列出了不一樣的優先級以及它們表明的內容。

除NoWork爲0外,較大的數字表示較低的優先級。例如,您可使用如下函數來檢查fiber的優先級是否至少與給定級別同樣高:

function matchesPriority(fiber, priority) {
  return fiber.pendingWorkPriority !== 0 &&
         fiber.pendingWorkPriority <= priority
}

此函數僅用於說明;它實際上並非React Fiber代碼庫的一部分。

scheduler使用優先級字段來搜索要執行的下一個工做單元。這個算法將在之後的章節中討論。

備用

flush

flush fiber是將其輸出呈如今屏幕上。

work-in-progress

還沒有完成的fiber;從概念上說,一個還沒有返回的堆棧幀。

在任什麼時候候,一個組件實例最多隻有兩條fiber對應:當前的,flushed fiber和work-in-progress fiber。

當前fiber的交替是work-in-progress,work-in-progress的交替是當前的fiber。

使用名爲cloneFiber的函數,能夠建立一個fiber的替代品。 cloneFiber不會老是建立一個新的對象,而是嘗試重用fiber的備用,若是它存在,最小化分配。

您應該將備用字段視爲實現細節,可是它在代碼庫中常常出現,所以在此討論它很是有用。

輸出

host component

React應用程序的葉子節點。它們特定於渲染環境(例如,在瀏覽器應用程序中,它們是「div」,「span」等)。在JSX中,它們使用小寫的標記名稱來表示。

從概念上講,fiber的輸出是一個函數的返回值。

每一個fiber最終都有輸出,但輸出僅由host組件在葉子節點建立。而後將輸出傳送到樹上。

輸出是最終呈現給渲染器,以便它能夠刷新渲染環境的變化。渲染者有責任定義輸出是如何建立和更新的。

將來部分

如今就是這樣,可是這個文件還遠遠沒有完成。之後的部分將介紹在整個生命週期中使用的算法。要涵蓋的主題包括:

  • scheduler如何找到要執行的下一個工做單元。
  • 如何經過fiber樹跟蹤和傳播優先級。
  • scheduler如何知道什麼時候暫停和恢復工做。
  • 工做如何被刷新並標記爲完整。
  • 反作用(如生命週期方法)如何工做。
  • 協程是什麼以及如何用它來實現上下文和佈局等功能。

相關視頻

What's Next for React (ReactNext 2016)

相關資料

一、徹底理解React Fiber

二、React 16 Fiber源碼速覽

三、React Fiber是什麼

四、如何理解 React Fiber 架構?

五、Under-the-hood-ReactJS

tree相關論文

A Survey on Tree Edit Distance and Related Problems

相關文章
相關標籤/搜索