React Fiber 原理介紹

原文鏈接https://blog.csdn.net/weixin_34253126/article/details/88585784

一栓始、前言

在 React Fiber 架構(gòu)面世一年多后钥弯,最近 React 又發(fā)布了最新版 16.8.0,又一激動(dòng)人心的特性:React Hooks 正式上線,讓我升級(jí) React 的意愿越來越強(qiáng)烈了量窘。在升級(jí)之前弯囊,不妨回到原點(diǎn),了解下人才濟(jì)濟(jì)的 React 團(tuán)隊(duì)為什么要大費(fèi)周章诱渤,重寫 React 架構(gòu)丐巫,而 Fiber 又是個(gè)什么概念。

二勺美、React 15 的問題

在頁面元素很多递胧,且需要頻繁刷新的場(chǎng)景下,React 15 會(huì)出現(xiàn)掉幀的現(xiàn)象赡茸。請(qǐng)看以下例子:
https://claudiopro.github.io/...

clipboard.png

其根本原因缎脾,是大量的計(jì)算任務(wù)阻塞了瀏覽器的 UI 渲染。默認(rèn)情況下占卧,JS 運(yùn)算遗菠、頁面布局和頁面繪制都是運(yùn)行在瀏覽器的主線程當(dāng)中,他們之間是互斥的關(guān)系屉栓。如果 JS 運(yùn)算持續(xù)占用主線程舷蒲,頁面就沒法得到及時(shí)的更新。

針對(duì)這一問題友多,React 團(tuán)隊(duì)從框架層面對(duì) web 頁面的運(yùn)行機(jī)制做了優(yōu)化牲平,得到很好的效果。

clipboard.png

三域滥、解題思路

解決主線程長(zhǎng)時(shí)間被 JS 運(yùn)算占用這一問題的基本思路纵柿,是將運(yùn)算切割為多個(gè)步驟,分批完成启绰。也就是說在完成一部分任務(wù)之后昂儒,將控制權(quán)交回給瀏覽器,讓瀏覽器有時(shí)間進(jìn)行頁面的渲染委可。等瀏覽器忙完之后渊跋,再繼續(xù)之前未完成的任務(wù)。為了達(dá)到這個(gè)效果着倾,需要借助瀏覽器的requestIdleCallback這一 API拾酝。官方的解釋是這樣:

window.requestIdleCallback()會(huì)在瀏覽器空閑時(shí)期依次調(diào)用函數(shù), 這就可以讓開發(fā)者在主事件循環(huán)中執(zhí)行后臺(tái)或低優(yōu)先級(jí)的任務(wù)卡者,而且不會(huì)對(duì)像動(dòng)畫和用戶交互這樣延遲觸發(fā)而且關(guān)鍵的事件產(chǎn)生影響蒿囤。函數(shù)一般會(huì)按先進(jìn)先調(diào)用的順序執(zhí)行,除非函數(shù)在瀏覽器調(diào)用它之前就到了它的超時(shí)時(shí)間崇决。

有了解題思路后材诽,我們?cè)賮砜纯?React 具體是怎么做的底挫。

四、React 的答卷

React 框架內(nèi)部的運(yùn)作可以分為 3 層:

  • Virtual DOM 層脸侥,描述頁面長(zhǎng)什么樣建邓。
  • Reconciler 層,負(fù)責(zé)調(diào)用組件生命周期方法湿痢,進(jìn)行 Diff 運(yùn)算等涝缝。
  • Renderer 層,根據(jù)不同的平臺(tái)譬重,渲染出相應(yīng)的頁面拒逮,比較常見的是 ReactDOM 和 ReactNative。

這次改動(dòng)最大的當(dāng)屬 Reconciler 層了臀规,React 團(tuán)隊(duì)也給它起了個(gè)新的名字滩援,叫Fiber Reconciler。這就引入另一個(gè)關(guān)鍵詞:Fiber塔嬉。

Fiber 其實(shí)指的是一種數(shù)據(jù)結(jié)構(gòu)玩徊,它可以用一個(gè)純 JS 對(duì)象來表示:

const fiber = {    stateNode,    // 節(jié)點(diǎn)實(shí)例    child,        // 子節(jié)點(diǎn)    sibling,      // 兄弟節(jié)點(diǎn)    return,       // 父節(jié)點(diǎn)}

為了加以區(qū)分,以前的 Reconciler 被命名為Stack Reconciler谨究。Stack Reconciler 運(yùn)作的過程是不能被打斷的恩袱,必須一條道走到黑:

clipboard.png

而 Fiber Reconciler 每執(zhí)行一段時(shí)間,都會(huì)將控制權(quán)交回給瀏覽器胶哲,可以分段執(zhí)行:

clipboard.png

為了達(dá)到這種效果畔塔,就需要有一個(gè)調(diào)度器 (Scheduler) 來進(jìn)行任務(wù)分配。任務(wù)的優(yōu)先級(jí)有六種:

  • synchronous鸯屿,與之前的Stack Reconciler操作一樣澈吨,同步執(zhí)行
  • task,在next tick之前執(zhí)行
  • animation寄摆,下一幀之前執(zhí)行
  • high谅辣,在不久的將來立即執(zhí)行
  • low,稍微延遲執(zhí)行也沒關(guān)系
  • offscreen婶恼,下一次render時(shí)或scroll時(shí)才執(zhí)行

優(yōu)先級(jí)高的任務(wù)(如鍵盤輸入)可以打斷優(yōu)先級(jí)低的任務(wù)(如Diff)的執(zhí)行桑阶,從而更快的生效。

Fiber Reconciler 在執(zhí)行過程中勾邦,會(huì)分為 2 個(gè)階段联逻。

clipboard.png
  • 階段一,生成 Fiber 樹检痰,得出需要更新的節(jié)點(diǎn)信息。這一步是一個(gè)漸進(jìn)的過程锨推,可以被打斷铅歼。
  • 階段二公壤,將需要更新的節(jié)點(diǎn)一次過批量更新,這個(gè)過程不能被打斷椎椰。

階段一可被打斷的特性厦幅,讓優(yōu)先級(jí)更高的任務(wù)先執(zhí)行,從框架層面大大降低了頁面掉幀的概率慨飘。

五确憨、Fiber 樹

Fiber Reconciler 在階段一進(jìn)行 Diff 計(jì)算的時(shí)候,會(huì)生成一棵 Fiber 樹瓤的。這棵樹是在 Virtual DOM 樹的基礎(chǔ)上增加額外的信息來生成的休弃,它本質(zhì)來說是一個(gè)鏈表。

clipboard.png

Fiber 樹在首次渲染的時(shí)候會(huì)一次過生成圈膏。在后續(xù)需要 Diff 的時(shí)候塔猾,會(huì)根據(jù)已有樹和最新 Virtual DOM 的信息,生成一棵新的樹稽坤。這顆新樹每生成一個(gè)新的節(jié)點(diǎn)丈甸,都會(huì)將控制權(quán)交回給主線程,去檢查有沒有優(yōu)先級(jí)更高的任務(wù)需要執(zhí)行尿褪。如果沒有睦擂,則繼續(xù)構(gòu)建樹的過程:

clipboard.png

如果過程中有優(yōu)先級(jí)更高的任務(wù)需要進(jìn)行,則 Fiber Reconciler 會(huì)丟棄正在生成的樹杖玲,在空閑的時(shí)候再重新執(zhí)行一遍顿仇。

在構(gòu)造 Fiber 樹的過程中,F(xiàn)iber Reconciler 會(huì)將需要更新的節(jié)點(diǎn)信息保存在Effect List當(dāng)中天揖,在階段二執(zhí)行的時(shí)候夺欲,會(huì)批量更新相應(yīng)的節(jié)點(diǎn)。

六今膊、總結(jié)

本文從 React 15 存在的問題出發(fā)些阅,介紹 React Fiber 解決問題的思路,并介紹了 Fiber Reconciler 的工作流程斑唬。從Stack ReconcilerFiber Reconciler市埋,源碼層面其實(shí)就是干了一件遞歸改循環(huán)的事情,日后有機(jī)會(huì)的話恕刘,我再結(jié)合源碼作進(jìn)一步的介紹缤谎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市褐着,隨后出現(xiàn)的幾起案子坷澡,更是在濱河造成了極大的恐慌,老刑警劉巖含蓉,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件频敛,死亡現(xiàn)場(chǎng)離奇詭異项郊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)斟赚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門着降,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拗军,你說我怎么就攤上這事任洞。” “怎么了发侵?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵交掏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我器紧,道長(zhǎng)耀销,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任铲汪,我火速辦了婚禮熊尉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掌腰。我一直安慰自己狰住,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布齿梁。 她就那樣靜靜地躺著催植,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勺择。 梳的紋絲不亂的頭發(fā)上创南,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音省核,去河邊找鬼稿辙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛气忠,可吹牛的內(nèi)容都是我干的邻储。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼旧噪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼吨娜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淘钟,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤宦赠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袱瓮,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缤骨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尺借。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡精拟,死狀恐怖燎斩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜂绎,我是刑警寧澤栅表,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站师枣,受9級(jí)特大地震影響怪瓶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜践美,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一洗贰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陨倡,春花似錦敛滋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杂曲,卻和暖如春庶艾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背擎勘。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工咱揍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人货抄。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓述召,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蟹地。 傳聞我的和親對(duì)象是個(gè)殘疾皇子积暖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348