React Fiber 中文文檔

React Fiber 結(jié)構(gòu)

介紹

React Fiber 是對React核心算法的重新實(shí)現(xiàn),也是React團(tuán)隊(duì)花了兩年時(shí)間研究的結(jié)晶揖闸。

React Fiber 的目標(biāo)是提升其對于動畫秉剑、布局替劈、手勢等場景的適用性慨畸。它的核心功能就是增量渲染:一種將渲染工作分解為多個(gè)區(qū)塊并將其分散到每一幀里面伞梯。

其他核心功能還包括隨著程序中新的update引起的暫定写隶、終止和繼續(xù)等倔撞;以及為不同任務(wù)分配優(yōu)先級;和最新的并發(fā)性慕趴。

關(guān)于文檔

Fiber引入了一些比較新的概念痪蝇,所以僅通過代碼很難理解鄙陡。這片文檔最開始是我在React項(xiàng)目中實(shí)現(xiàn)Fiber的筆記的集合。而隨著它的發(fā)展躏啰,我也逐漸意識到這些筆記對其他人也可能是比較有用的資源趁矾。

我盡量通過最簡單的語言,并明確定義關(guān)鍵術(shù)語來避免太專業(yè)化解釋给僵。在需要的時(shí)候還會有大量的外部鏈接來解釋毫捣。

請注意我并不是React團(tuán)隊(duì)中的一員,所以這篇文章也并非官方權(quán)威文檔帝际,但是我也找了React團(tuán)隊(duì)的的成員對其準(zhǔn)確性做了審查蔓同。

這也還是一個(gè)正在進(jìn)行的工作。Fiber還在持續(xù)演變蹲诀,在完成之前都有可能進(jìn)行很大的改動牌柄。設(shè)計(jì)文檔也會同步在這里更新,也歡迎大家來指正侧甫。

我的目標(biāo)是你讀完本篇文章之后對Fiber有足夠的了解,以便跟上后續(xù)的演變蹋宦,甚至為React作出貢獻(xiàn)披粟。

先決條件

強(qiáng)烈建議在讀本文之前理解一下概念:

  • React 組件 - "Component" 是非常重要的術(shù)語,需要牢牢掌握冷冗。
  • Reconciliation - 對React reconciliation算法的高級描述守屉。
  • React Basic Theoretical Concepts - 對沒有實(shí)現(xiàn)負(fù)擔(dān)的的React的概念描述. 剛開始的時(shí)候可能很多東西沒什么意義,但是隨著閱讀深入會更有意義蒿辙。
  • React Design Principles -需要特別關(guān)注scheduling部分拇泛。他很好的解釋了為什么會有React Fiber。

review

請?jiān)诖舜_認(rèn)理解了之前的先覺條件思灌。

在深入文檔之前俺叭,先了解幾個(gè)重要的概念。

什么是reconciliation泰偿?

reconciliation

React用來對比兩顆虛擬DOM樹的算法熄守,以判斷哪些DOM需要更新。

update

用于呈現(xiàn)React程序中的更改耗跛,一般是setState引發(fā)的裕照,最終重新渲染DOM。

React的核心思想是考慮全局更新调塌,這讓開發(fā)人員可以只考慮申明式來編寫代碼晋南,而不需要考慮中間過程。例如(A到B羔砾,B到C负间,C到A等等)偶妖。

事實(shí)上,有一點(diǎn)改動就更新整個(gè)app只存在于很少一部分app唉擂,而在真實(shí)的場景餐屎,這是很浪費(fèi)性能的。React對此做了優(yōu)化玩祟,可以保證性能的同時(shí)做到完整更新腹缩,這就是reconciliation 的部分功能。

reconciliation是虛擬DOM背后的核心算法空扎,高級一點(diǎn)的描述是:渲染React程序的時(shí)候藏鹊,將相應(yīng)的節(jié)點(diǎn)樹保存在內(nèi)存中。然后將該節(jié)點(diǎn)樹刷新到渲染環(huán)境中--例如瀏覽器转锈,它會轉(zhuǎn)化成一系列的DOM操作盘寡。當(dāng)程序更新的時(shí)候(通常是setState),會重新生成一顆新的樹撮慨。通過兩個(gè)節(jié)點(diǎn)樹的比較來計(jì)算這些更新需要哪些操作竿痰。

盡管Fiber是對reconciliation的重寫,但是React文檔中的高級算法的描述大致相同砌溺,主要在于:

  • 假如不同組件類型生成不同的樹影涉,react不會區(qū)分他們,二是直接替換规伐。
  • list主要用key來做區(qū)分蟹倾,這要求key必須“穩(wěn)定、可靠并且唯一”猖闪。

Reconciliation 和render

DOM只是react可以渲染的環(huán)境之一鲜棠,其他的還有通過react-native實(shí)現(xiàn)iOS和Android視圖的渲染(所以說虛擬DOM用詞很不恰當(dāng))。

react之所以能做到這一點(diǎn)是因?yàn)閞eact在設(shè)計(jì)的時(shí)候就已經(jīng)考慮到了將Reconciliation和render分開培慌。reconciler負(fù)責(zé)計(jì)算樹的更新豁陆,而render根據(jù)這些信息來負(fù)責(zé)應(yīng)用程序的更新。

這種分離意味著React DOM 和React Native 可以保證使用React Core提供的相同的reconciler而且使用不同的渲染方法吵护。

Fiber重新實(shí)現(xiàn)了reconciler 献联, 盡管渲染方法需要重新修改以支持(并利用)新的體系結(jié)構(gòu),但它基本上與渲染無關(guān)何址。

Scheduling

Scheduling

確定何時(shí)work的過程

work

必須執(zhí)行的任何計(jì)算里逆,work一般是指更新的結(jié)果(例如setState)。

React的 Design Principles 這篇文檔在這個(gè)主題上非常出色用爪,這里引用一下:

在當(dāng)前的實(shí)現(xiàn)中原押,react遞歸的遍歷樹,并在單個(gè)任務(wù)中調(diào)用整個(gè)更新后的render函數(shù)偎血,但是以后可能會考慮延遲一些更新诸衔,以免丟幀盯漂。

這是React 模式中常見的主題,一些流行的庫實(shí)現(xiàn)了“push”方法笨农,在有新數(shù)據(jù)更新的時(shí)候可用就缆。但是React堅(jiān)持使用“pull”方法,這可以將計(jì)算延遲到需要的時(shí)候谒亦。

React不是一個(gè)常規(guī)的數(shù)據(jù)處理庫竭宰,而是用于構(gòu)建用戶界面的庫。而我們認(rèn)為它在應(yīng)用程序中唯一的作用就是計(jì)算什么相關(guān)份招,什么不相關(guān)切揭。

如果有些東西不在當(dāng)前界面,我們可以延遲跟這個(gè)相關(guān)的邏輯锁摔。如果數(shù)據(jù)量太大廓旬,導(dǎo)致可能丟幀,我們會批量更新谐腰。我們可以將用戶交互(比如按鈕點(diǎn)擊引起的動畫)優(yōu)先于次要的后臺工作(例如網(wǎng)絡(luò)請求加載的新內(nèi)容)孕豹,以避免丟幀。

關(guān)鍵點(diǎn)在于:

  • 在用戶界面中十气,不必立即應(yīng)用每個(gè)更新巩步。事實(shí)上,這樣很浪費(fèi)性能桦踊,還會導(dǎo)致幀下降降低用戶體驗(yàn)。
  • 不同類型的更新有不同的優(yōu)先級:動畫更新優(yōu)先于數(shù)據(jù)存儲的更新终畅。
  • 基于“push”的程序要求程序(你籍胯,就是你)決定如何安排工作,而基于“pull”的模式(react)會更加智能离福,并幫你決定杖狼。

當(dāng)前React并沒有充分利用Scheduling的優(yōu)勢,一次更新會導(dǎo)致立刻重新渲染整個(gè)子樹妖爷。所以Fiber背后的思想就是徹底革新整個(gè)核心算法以充分利用Scheduling的優(yōu)勢蝶涩。


現(xiàn)在我們開始繼續(xù)深入Fiber的實(shí)現(xiàn),后面的內(nèi)容會更加“技術(shù)”絮识,請確保以上的內(nèi)容你已經(jīng)理解绿聘。

什么是Fiber

下面將討論React Fiber體系結(jié)構(gòu)的核心,F(xiàn)iber是比開發(fā)人員想象的低得多的抽象層次舌。如果你發(fā)現(xiàn)你理解不了熄攘,別沮喪,繼續(xù)堅(jiān)持下去彼念,最終肯定能理解挪圾。(等你理解的時(shí)候可以對本篇文章提點(diǎn)建議)

Here we go浅萧。


現(xiàn)在已經(jīng)確定,F(xiàn)iber的主要目標(biāo)是利用React的Scheduling的優(yōu)勢哲思,具體來說需要滿足以下幾點(diǎn):

  • 暫停工作洼畅,并回來
  • 為不同類型任務(wù)分配優(yōu)先級
  • 重用以前完成的工作
  • 不需要的時(shí)候終止任務(wù)

為了做到這一點(diǎn),我們需要一種將工作分解成多個(gè)單元的方法棚赔。從某種意義上來說帝簇,這就是Fiber。Fiber是一個(gè)最小工作單元忆嗜。

為了更近一步己儒,我們可以回顧一下 React components as functions of data, 通常表示為:

v = f(d)

因此,呈現(xiàn)整個(gè)react程序類似于調(diào)用一個(gè)函數(shù)捆毫,該函數(shù)的主體有屌用其他函數(shù)闪湾,以此類推。所以在思考Fiber的時(shí)候绩卤,這種類比會很有幫助途样。

計(jì)算機(jī)通常使用調(diào)用堆棧來跟蹤程序執(zhí)行的方式,一個(gè)函數(shù)被調(diào)用的時(shí)候濒憋,一個(gè)新的stack frame被添加到堆棧中何暇,這個(gè)stack frame也代表了這個(gè)函數(shù)的工作也被執(zhí)行了。

在處理UI的時(shí)候凛驮,較大的問題在于如果一次性執(zhí)行太多任務(wù)裆站,會導(dǎo)致動畫掉幀并顯得斷斷續(xù)續(xù)。而且黔夭,如果最新的更新取代了某些工作宏胯,則會顯得不太必要,因?yàn)榕c常規(guī)的功能相比本姥,組件的關(guān)注點(diǎn)會更多一點(diǎn)肩袍。

較新的瀏覽器(和React Native)實(shí)現(xiàn)了有助于解決此確切問題的API:equestIdleCallback安排在空閑期間調(diào)用的低優(yōu)先級函數(shù),而requestAnimationFrame安排在下一個(gè)動畫幀上調(diào)用的高優(yōu)先級函數(shù)婚惫。問題在于氛赐,想要使用這些API,你需要一種將render分解為增量單位的方法先舷,否則會一直執(zhí)行到堆棧為空艰管。

如果我們可以自定義調(diào)用堆棧的行為來優(yōu)化UI展現(xiàn),是不是特別棒蒋川?如果我們可以隨意調(diào)用堆棧蛙婴,并且手動操作堆棧,是不是更棒?

這就是React Fiber的目標(biāo)街图,F(xiàn)iber是堆棧的重新實(shí)現(xiàn)浇衬,也可以將其視為虛擬堆棧

重新實(shí)現(xiàn)堆棧的優(yōu)勢在于餐济,你可以將堆棧保存在內(nèi)存中耘擂,并根據(jù)需要(以及任何時(shí)候)執(zhí)行他們,這對于我們的目標(biāo)來說至關(guān)重要絮姆。

除了任務(wù)調(diào)度之外醉冤,手動處理堆棧還可以釋放并發(fā)和錯(cuò)誤邊界等功能。這些主題在以后的章節(jié)中會介紹篙悯。

下一節(jié)中蚁阳,我們更多的來研究一下Fiber的結(jié)構(gòu)。

Fiber的結(jié)構(gòu)

注意:隨著我們對實(shí)現(xiàn)細(xì)節(jié)的更加具體化鸽照,某些事項(xiàng)改變的可能性也增加了螺捐,如果發(fā)現(xiàn)任何錯(cuò)誤或者過時(shí)的信息,請?zhí)峤籔R矮燎。

具體來說定血,F(xiàn)iber是一個(gè)JavaScript的對象,其中包含有關(guān)組件诞外,以及輸入和輸出的信息澜沟。

Fiber類似于一個(gè)堆棧框架峡谊,但也對應(yīng)于一個(gè)組件的實(shí)例茫虽。

這里有一些Fiber的重要概念(包括但不限于)

typekey

在Fiber中,type和key的作用相同既们,就像React組件一樣(事實(shí)上濒析,創(chuàng)建一個(gè)元素的時(shí)候,F(xiàn)iber會復(fù)制這兩個(gè)字段)贤壁。

Fiber的type描述了他對一個(gè)的組件,對于復(fù)合組件埠忘,type是函數(shù)或者類組件本身脾拆,對于標(biāo)準(zhǔn)組件(例如div,span)莹妒,type是string名船。

從概念上來講,fiber是由堆椫嫉。框架執(zhí)行的函數(shù)(例如v = f(d))渠驼。

與type一起,key主要用來在reconciliation期間確定Fiber是否可重用鉴腻。

child and sibling

這些字段指向其他Fiber迷扇,描述了Fiber的遞歸樹結(jié)構(gòu)百揭。

child fiber對應(yīng)組件的render的返回值,所以在下面代碼中蜓席,Parent的fiber指向Child

function Parent() {
  return <Child />
}

sibling字段說明了返回多個(gè)子項(xiàng)的情況(Fiber中的新功能)器一。

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

child fiber在這種情況形成了一個(gè)一維列表,開頭是第一個(gè)子鏈厨内。所以在示例中祈秕,Parent的child是Child1,而Child1的兄弟節(jié)點(diǎn)是Child2

回到之前的函數(shù)類比, 你可以把 child fiber當(dāng)成 尾部函數(shù)雏胃。

return

return fiber 是當(dāng)程序處理完當(dāng)前fiber之后返回的fiber请毛。從概念上講,它與堆棧幀的返回地址相同瞭亮,也可以將其視為父fiber方仿。

如果一個(gè)fiber具有多個(gè)子fiber,那么每個(gè)子fiber返回的都是其父fiber街州。因此上面的例子中Child1Child2的 return fiber都是Parent兼丰。

pendingPropsmemoizedProps

從概念上來講,props是函數(shù)的參數(shù)唆缴,fiber的pendingProps在執(zhí)行開始時(shí)設(shè)置鳍征,而memoizedProps在結(jié)束的時(shí)候設(shè)置。

當(dāng)傳入的pendingPropsmemoizedProps相同的時(shí)候面徽,表示fiber可以重新使用之前的fiber艳丛,以避免重復(fù)的工作。

pendingWorkPriority(待處理的工作優(yōu)先級)

Fiber的工作優(yōu)先級用數(shù)字來表示趟紊,翻閱 ReactPriorityLevel模塊可以查詢每個(gè)值所代表的含義氮双。

除NoWork為0外,數(shù)字越大表示優(yōu)先級越低霎匈。例如戴差,您可以使用以下功能來檢查Fiber的優(yōu)先級是否至少與給定級別一樣高:

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

這只是一個(gè)說明示例,并非Fiber代碼庫的一部分

scheduler使用優(yōu)先級字段來查找下一個(gè)需要執(zhí)行的單元铛嘱,這個(gè)算法后面會討論暖释。

alternate

flush

fiber的flush是指將其輸出渲染到屏幕上。

work-in-progress

未完成的fiber墨吓,也就是為返回的堆棧幀球匕。

在任何時(shí)候,一個(gè)組件實(shí)例最多對應(yīng)兩個(gè)fiber:當(dāng)前的flushed fiber 和 work-in-progress fiber帖烘。

當(dāng)前fiber的備用fiber是work-in-progress fiber亮曹,反過來也是一樣。

fiber的備胎由cloneFiber延遲創(chuàng)建,而且并非每次都創(chuàng)建一個(gè)新的對象照卦,cloneFiber會嘗試重用fiber的備胎(如果有的話)式矫,從而最大程度的減少資源消耗。

alternate字段可以理解成實(shí)現(xiàn)細(xì)節(jié)窄瘟,但是在庫中經(jīng)常出現(xiàn)衷佃,所以在這里說明一下也是很有意義的。

output

host component

React程序中的葉節(jié)點(diǎn)蹄葱,一般是指特定的渲染環(huán)境(例如在瀏覽器中就是div 氏义,span等),在jsx中都是用小寫標(biāo)簽名來表示图云。

fiber的輸出一般都是函數(shù)的返回值惯悠。

每個(gè)fiber都會有output,但是output只會由host component在葉節(jié)點(diǎn)中創(chuàng)建竣况,并最終輸出到節(jié)點(diǎn)樹上克婶。

output是最終提供給渲染器的輸出,以便輸出到具體渲染環(huán)境(譯者注:react-dom 或者 react-native)中丹泉,如何定義輸出和輸入是渲染器的責(zé)任情萤。

Future sections(未來規(guī)劃)

目前只說這么多,但是這片文檔還遠(yuǎn)遠(yuǎn)不夠完整摹恨,以后的部分會描述在整個(gè)生命周期中使用的算法筋岛,涵蓋的主題包括以下:

  • scheduler如何找到下一個(gè)需要執(zhí)行的工作單元
  • 如何通過fiber樹來跟蹤和傳播優(yōu)先級
  • scheduler怎么知道什么時(shí)候暫停或者繼續(xù)
  • 如何刷新工作并標(biāo)記為完成
  • side-effects (例如生命周期)如何運(yùn)作
  • coroutine是什么以及如何用于實(shí)現(xiàn)上下文和布局等功能晒哄。

Related Videos

  • [What's Next for React (ReactNext 2016)](

本文為原創(chuàng)文章睁宰,轉(zhuǎn)載請保留原出處。原文地址:https:/eatong.cn/blog/14

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寝凌,一起剝皮案震驚了整個(gè)濱河市柒傻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌较木,老刑警劉巖红符,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伐债,居然都是意外死亡预侯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門泳赋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雌桑,“玉大人喇喉,你說我怎么就攤上這事祖今。” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵千诬,是天一觀的道長耍目。 經(jīng)常有香客問我,道長徐绑,這世上最難降的妖魔是什么邪驮? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮傲茄,結(jié)果婚禮上毅访,老公的妹妹穿的比我還像新娘。我一直安慰自己盘榨,他們只是感情好喻粹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著草巡,像睡著了一般守呜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上山憨,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天查乒,我揣著相機(jī)與錄音,去河邊找鬼郁竟。 笑死玛迄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枪孩。 我是一名探鬼主播憔晒,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蔑舞!你這毒婦竟也來了拒担?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤攻询,失蹤者是張志新(化名)和其女友劉穎从撼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钧栖,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡低零,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年特笋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抒和。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡草则,死狀恐怖潭陪,靈堂內(nèi)的尸體忽然破棺而出雄妥,到底是詐尸還是另有隱情最蕾,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布老厌,位于F島的核電站瘟则,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枝秤。R本人自食惡果不足惜醋拧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淀弹。 院中可真熱鬧丹壕,春花似錦、人聲如沸薇溃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痊焊。三九已至盏袄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薄啥,已是汗流浹背辕羽。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垄惧,地道東北人刁愿。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像到逊,于是被迫代替她去往敵國和親铣口。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355