摘要:它的主體特征是增量渲染能夠?qū)秩竟ぷ鞣指畛蓧K,并將其分散到多個(gè)幀中。實(shí)際上,這樣做可能會(huì)造成浪費(fèi),導(dǎo)致幀丟失并降低用戶(hù)體驗(yàn)。當(dāng)一個(gè)函數(shù)被執(zhí)行時(shí),一個(gè)新的堆棧框架被添加到堆棧中。該堆??虮硎居稍摵瘮?shù)執(zhí)行的工作。
原文
react-fiber-architecture
介紹React Fiber的目標(biāo)是提高其對(duì)動(dòng)畫(huà),布局和手勢(shì)等領(lǐng)域的適用性。它的主體特征是增量渲染:能夠?qū)秩竟ぷ鞣指畛蓧K,并將其分散到多個(gè)幀中。
其他主要功能包括在進(jìn)行更新時(shí)暫停,中止或重新使用工作的能力;為不同類(lèi)型的更新分配優(yōu)先權(quán)的能力;和新的并發(fā)原語(yǔ)。
關(guān)于這個(gè)文檔Fiber引入了幾個(gè)新穎的概念,很難通過(guò)查看代碼來(lái)完成。這個(gè)文檔是我們?cè)赗eact項(xiàng)目中隨著Fibre實(shí)現(xiàn)的一系列筆記開(kāi)始的。隨著它的發(fā)展,我意識(shí)到它也可能成為其他人的有用資源。
我會(huì)嘗試盡可能使用最普通的語(yǔ)言,并通過(guò)明確定義關(guān)鍵術(shù)語(yǔ)來(lái)避免行話。在可能的情況下,我也會(huì)大量連接外部資源。
請(qǐng)注意,我不在React團(tuán)隊(duì),也不會(huì)從任何權(quán)威機(jī)構(gòu)發(fā)言。這不是一個(gè)正式的文件。我已經(jīng)要求React團(tuán)隊(duì)的成員對(duì)其進(jìn)行檢查以確保準(zhǔn)確性。
這也是一個(gè)正在進(jìn)行的工作。Fiber是一個(gè)正在進(jìn)行的項(xiàng)目,在完成之前可能會(huì)經(jīng)歷重大的重構(gòu)。我也試圖在這里記錄它的設(shè)計(jì)。改進(jìn)和建議是非常受歡迎的。
我的目標(biāo)是在閱讀本文檔之后,您將會(huì)理解Fiber的實(shí)施情況,并最終甚至能夠回饋給React。
先決條件我強(qiáng)烈建議您在繼續(xù)之前熟悉以下資源:
React Components, Elements, and Instances - “ Component”通常是一個(gè)重載的術(shù)語(yǔ)。牢牢掌握這些術(shù)語(yǔ)至關(guān)重要。
Reconciliation - 對(duì)React reconciliation算法的高級(jí)描述。
React基本理論概念 - 對(duì)React概念模型的描述。其中一些內(nèi)容在第一次閱讀時(shí)可能沒(méi)有意義。沒(méi)關(guān)系,隨著時(shí)間的推移會(huì)更有意義。
React設(shè)計(jì)原則 - 特別注意scheduling部分。它很好的解釋了React Fiber的工作原理。
Review如果你還沒(méi)有看先決條件,請(qǐng)先看完它。
在我們深入研究新的東西之前,讓我們回顧一下幾個(gè)概念。
什么是reconciliationreconciliation
React算法,用來(lái)比較2顆樹(shù),以確定哪些部分需要改變。
更新
用于呈現(xiàn)React應(yīng)用的數(shù)據(jù)更改。通常是`setState`的結(jié)果。最終導(dǎo)致重新渲染。
React的API的核心思想認(rèn)為更新會(huì)導(dǎo)致整個(gè)應(yīng)用程序重新渲染。這允許開(kāi)發(fā)人員以聲明的方式進(jìn)行推理,而不用擔(dān)心如何有效地將應(yīng)用程序從任何特定狀態(tài)轉(zhuǎn)換到另一個(gè)狀態(tài)(從A到B,從B到C,從C到A等等)。
實(shí)際上,在每次更改時(shí)重新渲染整個(gè)應(yīng)用程序只適用于最瑣碎的應(yīng)用程序;在實(shí)際的應(yīng)用程序中,性能方面的代價(jià)非常高昂。 React具有優(yōu)化功能,可在保持良好性能的同時(shí)創(chuàng)建整個(gè)應(yīng)用程序需要重新呈現(xiàn)的外觀。這些優(yōu)化的大部分內(nèi)容是reconciliation的一部分。
Reconciliation是被普遍理解為“虛擬DOM”的算法。高級(jí)描述如下所示:當(dāng)您渲染React應(yīng)用程序時(shí),會(huì)生成一個(gè)描述應(yīng)用程序的節(jié)點(diǎn)樹(shù)并保存在內(nèi)存中。然后將該樹(shù)刷新到渲染環(huán)境 - 例如,在瀏覽器中,將其轉(zhuǎn)換為一組DOM操作。當(dāng)應(yīng)用程序更新(通常通過(guò)setState),生成一個(gè)新的樹(shù)。新樹(shù)與前一棵樹(shù)有區(qū)別,以計(jì)算需要更新呈現(xiàn)的應(yīng)用程序的操作。
盡管Fibre是對(duì)reconciler的徹頭徹尾的重寫(xiě),但React文檔中描述的高級(jí)算法在很大程度上是相同的。關(guān)鍵是:
假定不同的組件類(lèi)型產(chǎn)生實(shí)質(zhì)上不同的樹(shù)。React不會(huì)試圖區(qū)分它們,而是完全替換舊的樹(shù)。
列表的區(qū)分使用keys來(lái)執(zhí)行。關(guān)鍵應(yīng)該是“穩(wěn)定,可預(yù)測(cè),獨(dú)特”。
Reconciliation與渲染DOM只是React可以渲染的渲染環(huán)境之一,還可以通過(guò)React Native進(jìn)行本地iOS和Android視圖。 (這就是為什么“虛擬DOM”有點(diǎn)用詞不當(dāng))。
它可以支持如此多目標(biāo)是因?yàn)镽eact的設(shè)計(jì)使reconciliation和渲染是分開(kāi)的階段。reconciler完成了計(jì)算樹(shù)的哪些部分已經(jīng)改變的工作;渲染器然后使用該信息實(shí)際更新呈現(xiàn)的應(yīng)用程序。
這種分離意味著React DOM和React Native可以使用他們自己的渲染器,同時(shí)共享由React核心提供的相同的reconciler。
Fiber重新實(shí)現(xiàn)了reconciler。雖然渲染者需要改變以支持(并利用)新的架構(gòu),但它并不主要關(guān)心渲染。
Schedulingscheduling
確定何時(shí)應(yīng)該進(jìn)行工作的過(guò)程。
工作
任何必須執(zhí)行的計(jì)算。工作通常是更新的結(jié)果(例如setState)。
React的設(shè)計(jì)原則文檔在這個(gè)主題上非常好,我只是在這里引用它:
在當(dāng)前實(shí)現(xiàn)中,React遞歸地遍歷樹(shù),并在單個(gè)tick中調(diào)用整個(gè)更新樹(shù)的render函數(shù)。但是,將來(lái)可能會(huì)延遲一些更新以避免丟幀。這是React設(shè)計(jì)中的一個(gè)常見(jiàn)主題。當(dāng)新數(shù)據(jù)可用時(shí),一些流行的庫(kù)實(shí)現(xiàn)了“push”方法,其中計(jì)算被執(zhí)行。然而,React堅(jiān)持“pull”的方法,計(jì)算可以延遲到必要的時(shí)候。
React不是一個(gè)通用的數(shù)據(jù)處理庫(kù)。這是一個(gè)建立用戶(hù)界面的庫(kù)。我們認(rèn)為它是唯一定位在一個(gè)應(yīng)用程序來(lái)知道現(xiàn)在哪些計(jì)算是相關(guān)的,哪些不是。
如果有什么東西在屏幕外,我們可以推遲任何與之相關(guān)的邏輯。如果數(shù)據(jù)比幀速率更快到達(dá),我們可以合并批量更新。我們可以?xún)?yōu)先考慮來(lái)自用戶(hù)交互的工作(比如點(diǎn)擊按鈕造成的動(dòng)畫(huà))而不是重要的后臺(tái)工作(比如剛剛從網(wǎng)絡(luò)加載的新內(nèi)容),以避免丟失幀。
關(guān)鍵是:
在用戶(hù)界面中,沒(méi)有必要立即應(yīng)用每個(gè)更新。實(shí)際上,這樣做可能會(huì)造成浪費(fèi),導(dǎo)致幀丟失并降低用戶(hù)體驗(yàn)。
不同類(lèi)型的更新具有不同的優(yōu)先級(jí) - 動(dòng)畫(huà)更新需要比從數(shù)據(jù)存儲(chǔ)更新更快地完成。
基于push的方法要求應(yīng)用程序(您,程序員)決定如何安排工作?;趐ull的方法可以使框架(React)更加智能,并為您做出決定。
目前,React并沒(méi)有以重要的方式利用scheduling;整個(gè)子樹(shù)的更新結(jié)果立即被重新渲染。檢修React的核心算法以利用scheduling是Fiber背后的驅(qū)動(dòng)理念。
現(xiàn)在我們已經(jīng)準(zhǔn)備好進(jìn)入Fiber的實(shí)施。接下來(lái)的部分比我們迄今為止所討論的更具技術(shù)性。在繼續(xù)之前,請(qǐng)確保您對(duì)前面的內(nèi)容感到滿(mǎn)意。
什么是fiber?我們即將討論React Fiber架構(gòu)的核心。Fiber比應(yīng)用程序開(kāi)發(fā)人員通常所想的要底層抽象得多。如果你對(duì)自己的理解感到沮喪,不要感到氣餒。繼續(xù)嘗試,最終會(huì)有意義的。 (當(dāng)你最終得到它,請(qǐng)建議如何改善這一部分。)
開(kāi)始了!
我們已經(jīng)確定,F(xiàn)iber的主要目標(biāo)是使React能夠利用scheduling。具體來(lái)說(shuō),我們需要能夠
暫停工作,稍后再回來(lái)。
為不同類(lèi)型的工作分配優(yōu)先權(quán)。
重復(fù)以前完成的工作。
如果不再需要,請(qǐng)中止工作。
為了做到這一點(diǎn),我們首先需要一種把工作分解成單元的方法。從某種意義上說(shuō),這就是fiber。fiber代表一個(gè)工作單元。
為了更進(jìn)一步,讓我們回到React組件作為數(shù)據(jù)函數(shù)的概念,通常表達(dá)為
v = f(d)
因此渲染一個(gè)React應(yīng)用程序類(lèi)似于調(diào)用其主體包含對(duì)其他函數(shù)的調(diào)用的函數(shù),等等。這個(gè)比喻在思考fiber時(shí)很有用。
計(jì)算機(jī)通常跟蹤程序執(zhí)行的方式是使用調(diào)用堆棧。當(dāng)一個(gè)函數(shù)被執(zhí)行時(shí),一個(gè)新的堆??蚣鼙惶砑拥蕉褩V小T摱褩?虮硎居稍摵瘮?shù)執(zhí)行的工作。
在處理UI時(shí),問(wèn)題是如果一次執(zhí)行了太多的工作,它可能會(huì)導(dǎo)致動(dòng)畫(huà)丟幀,看起來(lái)不穩(wěn)定。更重要的是,如果某些工作被更新的更新所取代,那么這些工作可能是不必要的。這是UI組件和函數(shù)之間的比較失敗的地方,因?yàn)榻M件比一般的函數(shù)具有更多特定的問(wèn)題。
較新的瀏覽器(和React Native)實(shí)現(xiàn)了API來(lái)幫助解決這個(gè)確切的問(wèn)題:requestIdleCallback schedules在空閑期間被調(diào)用的低優(yōu)先級(jí)函數(shù),requestAnimationFrame schedules在下一個(gè)動(dòng)畫(huà)幀上被調(diào)用的高優(yōu)先級(jí)函數(shù)。問(wèn)題是,為了使用這些API,您需要一種方法來(lái)將渲染工作分解為增量單元。如果只依賴(lài)調(diào)用堆棧,它將繼續(xù)工作,直到堆棧為空。
如果我們可以自定義調(diào)用堆棧的行為來(lái)優(yōu)化呈現(xiàn)UI,這不是很好嗎?如果我們可以隨意中斷調(diào)用堆棧并手動(dòng)操作堆棧幀,這不是很好嗎?
這就是React Fiber的目的。Fiber重新實(shí)現(xiàn)堆棧,專(zhuān)門(mén)用于React組件。您可以將單個(gè)fiber視為虛擬堆棧幀。
重新實(shí)現(xiàn)堆棧的好處是你可以將堆棧幀保存在內(nèi)存中,然后執(zhí)行它們(無(wú)論何時(shí))。這對(duì)于完成我們安排的目標(biāo)至關(guān)重要。
除了調(diào)度scheduling,還有手動(dòng)處理堆棧幀解鎖了諸如并發(fā)和錯(cuò)誤邊界之類(lèi)的功能的潛力。我們將在以后的章節(jié)中介紹這些話題。
在下一節(jié)中,我們將更多地關(guān)注fiber的結(jié)構(gòu)。
fiber的結(jié)構(gòu)注意:隨著我們對(duì)實(shí)現(xiàn)細(xì)節(jié)的更具體的了解,事情可能發(fā)生變化的可能性會(huì)增加。如果您發(fā)現(xiàn)任何錯(cuò)誤或過(guò)時(shí)的信息,請(qǐng)?zhí)峤籔R。
具體而言,fiber是一個(gè)JavaScript對(duì)象,包含有關(guān)組件,其輸入和輸出的信息。
fiber對(duì)應(yīng)于堆棧幀,但也對(duì)應(yīng)于組件的一個(gè)實(shí)例。
這是一些屬于fiber的重要領(lǐng)域。 (這個(gè)清單并不詳盡。)
type and keyfiber的type和key與React元素的作用相同。 (實(shí)際上,當(dāng)從一個(gè)元素創(chuàng)建一個(gè)fiber時(shí),這兩個(gè)字段直接被復(fù)制過(guò)來(lái)。)
fiber的type描述了它對(duì)應(yīng)的組件。對(duì)于復(fù)合組件,類(lèi)型是函數(shù)或類(lèi)組件本身。對(duì)于host組件(div,span等),類(lèi)型是一個(gè)字符串。
從概念上講,type是函數(shù)(如在v = f(d)中),其執(zhí)行被棧幀跟蹤。
隨著type的不同,在reconciliation期間使用key來(lái)確定fiber是否可以重新使用。
child and sibling這些字段指向其他fiber,描述fiber的遞歸樹(shù)狀結(jié)構(gòu)。
子fiber對(duì)應(yīng)于組件渲染方法返回的值。所以在下面的例子中
function Parent() { return}
Parent的child fiber對(duì)應(yīng)于Child。
兄弟領(lǐng)域說(shuō)明了渲染返回多個(gè)children的情況(Fiber中的一個(gè)新特性):
function Parent() { return [, ] }
child的fiber形成一個(gè)單一的鏈表,head是第一個(gè)child。所以在這個(gè)例子中,Parent的child是Child1,而Child1的兄弟是Child2。
回到我們的功能比喻,你可以把一個(gè)子fiber想象成一個(gè)尾調(diào)用函數(shù)。
returnreturn fiber是程序在處理完當(dāng)前fiber后返回的fiber。它在概念上與堆棧幀的返回地址相同。它也可以被認(rèn)為是parent fiber。
如果fiber具有多個(gè)子fiber,則每個(gè)子fiber的return fiber是parent。所以在前面的例子中,Child1和Child2的return fiber是Parent。
pendingProps 和 memoizedProps從概念上講,props是一個(gè)函數(shù)的arguments。一個(gè)fiber的pendingProps在執(zhí)行開(kāi)始時(shí)被設(shè)置,memoizedProps被設(shè)置在最后。
當(dāng)傳入的pendingProps等于memoizedProps時(shí),它表明fiber的先前輸出可以被重復(fù)使用,避免不必要的工作。
pendingWorkPriority一個(gè)數(shù)字,表示fiber所代表的工作的優(yōu)先級(jí)。 ReactPriorityLevel模塊列出了不同的優(yōu)先級(jí)以及它們代表的內(nèi)容。
除NoWork為0外,較大的數(shù)字表示較低的優(yōu)先級(jí)。例如,您可以使用以下函數(shù)來(lái)檢查fiber的優(yōu)先級(jí)是否至少與給定級(jí)別一樣高:
function matchesPriority(fiber, priority) { return fiber.pendingWorkPriority !== 0 && fiber.pendingWorkPriority <= priority }
此函數(shù)僅用于說(shuō)明;它實(shí)際上并不是React Fiber代碼庫(kù)的一部分。
scheduler使用優(yōu)先級(jí)字段來(lái)搜索要執(zhí)行的下一個(gè)工作單元。這個(gè)算法將在以后的章節(jié)中討論。
備用flush
flush fiber是將其輸出呈現(xiàn)在屏幕上。
work-in-progress
尚未完成的fiber;從概念上說(shuō),一個(gè)尚未返回的堆棧幀。
在任何時(shí)候,一個(gè)組件實(shí)例最多只有兩條fiber對(duì)應(yīng):當(dāng)前的,flushed fiber和work-in-progress fiber。
當(dāng)前fiber的交替是work-in-progress,work-in-progress的交替是當(dāng)前的fiber。
使用名為cloneFiber的函數(shù),可以創(chuàng)建一個(gè)fiber的替代品。 cloneFiber不會(huì)總是創(chuàng)建一個(gè)新的對(duì)象,而是嘗試重用fiber的備用,如果它存在,最小化分配。
您應(yīng)該將備用字段視為實(shí)現(xiàn)細(xì)節(jié),但是它在代碼庫(kù)中經(jīng)常出現(xiàn),因此在此討論它非常有用。
輸出host component
React應(yīng)用程序的葉子節(jié)點(diǎn)。它們特定于渲染環(huán)境(例如,在瀏覽器應(yīng)用程序中,它們是“div”,“span”等)。在JSX中,它們使用小寫(xiě)的標(biāo)記名稱(chēng)來(lái)表示。
從概念上講,fiber的輸出是一個(gè)函數(shù)的返回值。
每個(gè)fiber最終都有輸出,但輸出僅由host組件在葉子節(jié)點(diǎn)創(chuàng)建。然后將輸出傳送到樹(shù)上。
輸出是最終呈現(xiàn)給渲染器,以便它可以刷新渲染環(huán)境的變化。渲染者有責(zé)任定義輸出是如何創(chuàng)建和更新的。
未來(lái)部分現(xiàn)在就是這樣,但是這個(gè)文件還遠(yuǎn)遠(yuǎn)沒(méi)有完成。以后的部分將介紹在整個(gè)生命周期中使用的算法。要涵蓋的主題包括:
scheduler如何找到要執(zhí)行的下一個(gè)工作單元。
如何通過(guò)fiber樹(shù)跟蹤和傳播優(yōu)先級(jí)。
scheduler如何知道何時(shí)暫停和恢復(fù)工作。
工作如何被刷新并標(biāo)記為完整。
副作用(如生命周期方法)如何工作。
協(xié)程是什么以及如何用它來(lái)實(shí)現(xiàn)上下文和布局等功能。
相關(guān)視頻What"s Next for React (ReactNext 2016)
相關(guān)資料1、完全理解React Fiber
2、React 16 Fiber源碼速覽
3、React Fiber是什么
4、如何理解 React Fiber 架構(gòu)?
5、Under-the-hood-ReactJS
tree相關(guān)論文A Survey on Tree Edit Distance and Related Problems
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92470.html
摘要:架構(gòu)理解引用原文是核心算法正在進(jìn)行的重新實(shí)現(xiàn)。構(gòu)建的過(guò)程就是的過(guò)程,通過(guò)來(lái)調(diào)度執(zhí)行一組任務(wù),每完成一個(gè)任務(wù)后回來(lái)看看有沒(méi)有插隊(duì)的更緊急的,把時(shí)間控制權(quán)交還給主線程,直到下一次回調(diào)再繼續(xù)構(gòu)建。 React Fiber 架構(gòu)理解 引用原文:React Fiber ArchitectureReact Fiber is an ongoing reimplementation of Reacts...
摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來(lái)很順暢。通過(guò)進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...
摘要:如果你的運(yùn)行緩慢,你可以考慮是否能優(yōu)化請(qǐng)求,減少對(duì)的操作,盡量少的操,或者犧牲其它的來(lái)?yè)Q取性能。在認(rèn)識(shí)描述這些核心元素的過(guò)程中,我們也會(huì)分享一些當(dāng)我們構(gòu)建的時(shí)候遵守的一些經(jīng)驗(yàn)規(guī)則,一個(gè)應(yīng)用應(yīng)該保持健壯和高性能來(lái)維持競(jìng)爭(zhēng)力。 一個(gè)開(kāi)源的前端錯(cuò)誤收集工具 frontend-tracker,你值得收藏~ 蒲公英團(tuán)隊(duì)最近開(kāi)發(fā)了一款前端錯(cuò)誤收集工具,名叫 frontend-tracker ,這款...
閱讀 1414·2021-09-26 09:55
閱讀 1946·2019-08-30 12:45
閱讀 1098·2019-08-29 11:20
閱讀 3581·2019-08-26 11:33
閱讀 3462·2019-08-26 10:55
閱讀 1718·2019-08-23 17:54
閱讀 2413·2019-08-23 15:55
閱讀 2372·2019-08-23 14:23