摘要:它的主體特征是增量渲染能夠將渲染工作分割成塊,并將其分散到多個幀中。實際上,這樣做可能會造成浪費,導致幀丟失并降低用戶體驗。當一個函數被執行時,一個新的堆棧框架被添加到堆棧中。該堆棧框表示由該函數執行的工作。
原文
react-fiber-architecture
介紹React Fiber的目標是提高其對動畫,布局和手勢等領域的適用性。它的主體特征是增量渲染:能夠將渲染工作分割成塊,并將其分散到多個幀中。
其他主要功能包括在進行更新時暫停,中止或重新使用工作的能力;為不同類型的更新分配優先權的能力;和新的并發原語。
關于這個文檔Fiber引入了幾個新穎的概念,很難通過查看代碼來完成。這個文檔是我們在React項目中隨著Fibre實現的一系列筆記開始的。隨著它的發展,我意識到它也可能成為其他人的有用資源。
我會嘗試盡可能使用最普通的語言,并通過明確定義關鍵術語來避免行話。在可能的情況下,我也會大量連接外部資源。
請注意,我不在React團隊,也不會從任何權威機構發言。這不是一個正式的文件。我已經要求React團隊的成員對其進行檢查以確保準確性。
這也是一個正在進行的工作。Fiber是一個正在進行的項目,在完成之前可能會經歷重大的重構。我也試圖在這里記錄它的設計。改進和建議是非常受歡迎的。
我的目標是在閱讀本文檔之后,您將會理解Fiber的實施情況,并最終甚至能夠回饋給React。
先決條件我強烈建議您在繼續之前熟悉以下資源:
React Components, Elements, and Instances - “ Component”通常是一個重載的術語。牢牢掌握這些術語至關重要。
Reconciliation - 對React reconciliation算法的高級描述。
React基本理論概念 - 對React概念模型的描述。其中一些內容在第一次閱讀時可能沒有意義。沒關系,隨著時間的推移會更有意義。
React設計原則 - 特別注意scheduling部分。它很好的解釋了React Fiber的工作原理。
Review如果你還沒有看先決條件,請先看完它。
在我們深入研究新的東西之前,讓我們回顧一下幾個概念。
什么是reconciliationreconciliation
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。雖然渲染者需要改變以支持(并利用)新的架構,但它并不主要關心渲染。
Schedulingscheduling
確定何時應該進行工作的過程。
工作
任何必須執行的計算。工作通常是更新的結果(例如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 keyfiber的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}
Parent的child fiber對應于Child。
兄弟領域說明了渲染返回多個children的情況(Fiber中的一個新特性):
function Parent() { return [, ] }
child的fiber形成一個單一的鏈表,head是第一個child。所以在這個例子中,Parent的child是Child1,而Child1的兄弟是Child2。
回到我們的功能比喻,你可以把一個子fiber想象成一個尾調用函數。
returnreturn 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)
相關資料1、完全理解React Fiber
2、React 16 Fiber源碼速覽
3、React Fiber是什么
4、如何理解 React Fiber 架構?
5、Under-the-hood-ReactJS
tree相關論文A Survey on Tree Edit Distance and Related Problems
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92470.html
摘要:架構理解引用原文是核心算法正在進行的重新實現。構建的過程就是的過程,通過來調度執行一組任務,每完成一個任務后回來看看有沒有插隊的更緊急的,把時間控制權交還給主線程,直到下一次回調再繼續構建。 React Fiber 架構理解 引用原文:React Fiber ArchitectureReact Fiber is an ongoing reimplementation of Reacts...
摘要:因為版本將真正廢棄這三生命周期到目前為止,的渲染機制遵循同步渲染首次渲染,更新時更新時卸載時期間每個周期函數各司其職,輸入輸出都是可預測,一路下來很順暢。通過進一步觀察可以發現,預廢棄的三個生命周期函數都發生在虛擬的構建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時間準備前端招聘事項...
摘要:如果你的運行緩慢,你可以考慮是否能優化請求,減少對的操作,盡量少的操,或者犧牲其它的來換取性能。在認識描述這些核心元素的過程中,我們也會分享一些當我們構建的時候遵守的一些經驗規則,一個應用應該保持健壯和高性能來維持競爭力。 一個開源的前端錯誤收集工具 frontend-tracker,你值得收藏~ 蒲公英團隊最近開發了一款前端錯誤收集工具,名叫 frontend-tracker ,這款...
閱讀 1377·2021-09-26 09:55
閱讀 1917·2019-08-30 12:45
閱讀 1055·2019-08-29 11:20
閱讀 3554·2019-08-26 11:33
閱讀 3411·2019-08-26 10:55
閱讀 1685·2019-08-23 17:54
閱讀 2381·2019-08-23 15:55
閱讀 2341·2019-08-23 14:23