首頁  >  文章  >  web前端  >  react中什麼是fiber

react中什麼是fiber

青灯夜游
青灯夜游原創
2022-03-22 13:03:084895瀏覽

Fiber是React新的調度演算法,是對核心演算法的一次重新實作。 React Fiber把更新過程碎片化,每執行完一段更新過程,就把控制權交還給React負責任務協調的模組,看看有沒有其他緊急任務要做,如果有緊急任務,就去做緊急任務。

react中什麼是fiber

本教學操作環境:Windows7系統、react17.0.1版、Dell G3電腦。

react16 版本之後引入了 fiber,整個架構層面的 調度、協調、diff 演算法以及渲染等都與 fiber 密切相關。

React Fiber是什麼東西呢?

react在進行元件渲染時,從setState開始到渲染完成整個過程是同步的(「一氣呵成」)。如果需要渲染的元件比較龐大,js執行會佔據主執行緒時間較長,會導致頁面響應度變差,使得react在動畫、手勢等應用程式中效果比較差。

為了解決這個問題,react團隊經過兩年的工作,重寫了react中核心演算法-reconciliation。並在v16版本中發布了這個新的功能。為了區別之前和之後的reconciler,通常將先前的reconciler稱為stack reconciler,重寫後的稱為fiber reconciler,簡稱為Fiber。

官方的一句話解釋是「React Fiber是對核心演算法的一次重新實現」。

Fiber 可以提升複雜React 應用程式的可響應性和效能。 Fiber 也就是React新的調度演算法(reconciliation algorithm)

React Fiber 把更新過程片段化,每執行完一段更新過程,就把控制權交還給React 負責任務協調的模組,看看有沒有其他緊急任務要做,如果沒有就繼續更新,如果有緊急任務,那就去做緊急任務。

react在進行元件渲染時,從setState開始到渲染完成整個過程是同步的(「一氣呵成」)。如果需要渲染的元件比較龐大,js執行會佔據主執行緒時間較長,會導致頁面響應度變差,使得react在動畫、手勢等應用程式中效果比較差。

為了解決這個問題,react團隊經過兩年的工作,重寫了react中核心演算法-reconciliation。並在v16版本中發布了這個新的功能。為了區別之前和之後的reconciler,通常將先前的reconciler稱為stack reconciler,重寫後的稱為fiber reconciler,簡稱為Fiber。

react中什麼是fiber

react中什麼是fiber

卡頓原因

Stack reconciler的工作流程很像函數的呼叫過程。父組件裡調子組件,可以類比為函數的遞歸(這也是為什麼被稱為stack reconciler的原因)。在setState後,react會立即開始reconciliation過程,從父節點(Virtual DOM)開始遍歷,以找出不同。將所有的Virtual DOM遍歷完成後,reconciler才能給出當前需要修改真實DOM的信息,並傳遞給renderer,進行渲染,然後屏幕上才會顯示此次更新內容。對於特別龐大的vDOM樹來說,reconciliation過程會很長(x00ms),在這段期間,主線程是被js佔用的,因此任何交互、佈局、渲染都會停止,給用戶的感覺就是頁面被卡住了。

react中什麼是fiber

Scheduler

scheduling(調度)是fiber reconciliation的一個過程,主要決定應該在何時做什麼。 ?的過程表明在stack reconciler中,reconciliation是“一氣呵成”,對於函數來說,這沒什麼問題,因為我們只想要函數的運行結果,但對於UI來說還需要考慮以下問題:

  • 並不是所有的state更新都需要立即顯示出來,例如螢幕以外的部分的更新
  • 並不是所有的更新優先順序都是一樣的,例如使用者輸入的回應優先級要比透過請求填充內容的回應優先權更高
  • 理想情況下,對於某些高優先權的操作,應該是可以打斷低優先權的操作執行的,例如使用者輸入時,頁面的某個評論還在reconciliation,應該優先響應用戶輸入

所以理想狀況下reconciliation的過程應該是像下圖所示一樣,每次只做一個很小的任務,做完後能夠“喘口氣”,回到主線程看下有沒有什麼更高優先級的任務需要處理,如果又則先處理更高優先級的任務,沒有則繼續執行(cooperative scheduling 合作式調度)。

react中什麼是fiber

任務分割 fiber-tree & fiber

先看一下stack-reconciler下的react是怎麼運作的。在程式碼中建立(或更新)一些元素,react會根據這些元素建立(或更新)Virtual DOM,然後react根據更新前後virtual DOM的區別,去修改真正的DOM。注意,在stack reconciler下,DOM的更新是同步的,也就是說,在virtual DOM的比對過程中,發現一個instance有更新,會立即執行DOM操作

react中什麼是fiber

而fiber-conciler下,操作是可以分成很多小部分,並且可以中斷的,所以同步操作DOM可能會導致fiber-tree與實際DOM的不同步。對於每個節點來說,其不光儲存了對應元素的基本信息,還要保存一些用於任務調度的信息。因此,fiber只是一個對象,表徵reconciliation階段所能分割的最小工作單元,和上圖的react instance一一對應。透過stateNode屬性管理Instance本身的特性。透過child和sibling來表徵目前工作單元的下一個工作單元,return表示處理完成後返回結果所要合併的目標,通常指向父節點。整個結構是一個鍊錶樹。每個工作單元(fiber)執行完成後,都會檢視是否仍繼續擁有主執行緒時間片,如果有繼續下一個,如果沒有則先處理其他高優先權事務,等主執行緒空閒下來繼續執行。

react中什麼是fiber

fiber {  	stateNode: {},    child: {},    return: {},    sibling: {},
}复制代码

舉例

目前頁麵包含一個列表,透過該列表渲染出一個button和一組Item,Item中包含一個div,其中的內容為數字。透過點擊button,可以使清單中的所有數字平方。另外有一個按鈕,點擊可以調整字體大小。

react中什麼是fiber

頁面渲染完成後,就會初始化產生一個fiber-tree。初始化fiber-tree和初始化Virtual DOM tree沒什麼差別,這裡就不再贅述。

react中什麼是fiber

於此同時,react也會維護一個workInProgressTree。 workInProgressTree用於計算更新,完成reconciliation過程。

react中什麼是fiber

使用者點選平方按鈕後,利用各個元素平方後的list呼叫setState,react會把目前的更新送入list元件對應的update queue中。但是react並不會立即執行比較並修改DOM的操作。而是交給scheduler去處理。

react中什麼是fiber

scheduler會根據目前主執行緒的使用情況去處理這次update。為了實現這種特性,使用了requestIdelCallbackAPI。對於不支援這個API的瀏覽器,react會加上pollyfill。

總的來講,通常,客戶端執行緒執行任務時會以幀的形式劃分,大部分設備控制在30-60幀是不會影響使用者體驗;在兩個執行幀之間,主執行緒通常會有一小段空閒時間,requestIdleCallback可以在這個空閒期(Idle Period)呼叫空閒期回呼(Idle Callback),執行一些任務

1react中什麼是fiber

  • 低优先级任务由requestIdleCallback处理;

  • 高优先级任务,如动画相关的由requestAnimationFrame处理;

  • requestIdleCallback可以在多个空闲期调用空闲期回调,执行任务;

  • requestIdleCallback方法提供deadline,即任务执行限制时间,以切分任务,避免长时间执行,阻塞UI渲染而导致掉帧;

一旦reconciliation过程得到时间片,就开始进入work loop。work loop机制可以让react在计算状态和等待状态之间进行切换。为了达到这个目的,对于每个loop而言,需要追踪两个东西:下一个工作单元(下一个待处理的fiber);当前还能占用主线程的时间。第一个loop,下一个待处理单元为根节点。

1react中什麼是fiber

因为根节点上的更新队列为空,所以直接从fiber-tree上将根节点复制到workInProgressTree中去。根节点中包含指向子节点(List)的指针。

1react中什麼是fiber

根节点没有什么更新操作,根据其child指针,接下来把List节点及其对应的update queue也复制到workinprogress中。List插入后,向其父节点返回,标志根节点的处理完成。

1react中什麼是fiber

根节点处理完成后,react此时检查时间片是否用完。如果没有用完,根据其保存的下个工作单元的信息开始处理下一个节点List。

1react中什麼是fiber

接下来进入处理List的work loop,List中包含更新,因此此时react会调用setState时传入的updater funciton获取最新的state值,此时应该是[1,4,9]。通常我们现在在调用setState传入的是一个对象,但在使用fiber conciler时,必须传入一个函数,函数的返回值是要更新的state。react从很早的版本就开始支持这种写法了,不过通常没有人用。在之后的react版本中,可能会废弃直接传入对象的写法。

setState({}, callback); // stack concilersetState(() => { return {} }, callback); // fiber conciler复制代码

在获取到最新的state值后,react会更新List的state和props值,然后调用render,然后得到一组通过更新后的list值生成的elements。react会根据生成elements的类型,来决定fiber是否可重用。对于当前情况来说,新生成的elments类型并没有变(依然是Button和Item),所以react会直接从fiber-tree中复制这些elements对应的fiber到workInProgress 中。并给List打上标签,因为这是一个需要更新的节点。

1react中什麼是fiber

List节点处理完成,react仍然会检查当前时间片是否够用。如果够用则处理下一个,也就是button。加入这个时候,用户点击了放大字体的按钮。这个放大字体的操作,纯粹由js实现,跟react无关。但是操作并不能立即生效,因为react的时间片还未用完,因此接下来仍然要继续处理button。

1react中什麼是fiber

button没有任何子节点,所以此时可以返回,并标志button处理完成。如果button有改变,需要打上tag,但是当前情况没有,只需要标记完成即可。

1react中什麼是fiber

老规矩,处理完一个节点先看时间够不够用。注意这里放大字体的操作已经在等候释放主线程了。

1react中什麼是fiber

接下来处理第一个item。通过shouldComponentUpdate钩子可以根据传入的props判断其是否需要改变。对于第一个Item而言,更改前后都是1,所以不会改变,shouldComponentUpdate返回false,复制div,处理完成,检查时间,如果还有时间进入第二个Item。

第二个Item shouldComponentUpdate返回true,所以需要打上tag,标志需要更新,复制div,调用render,讲div中的内容从2更新为4,因为div有更新,所以标记div。当前节点处理完成。

react中什麼是fiber

對於上面這種情況,div已經是葉子節點,且沒有任何兄弟節點,且其值已經更新,這時候,需要將此節點改變產生的effect合併到父節點中。此時react會維護一個列表,其中記錄所有產生effect的元素。

2react中什麼是fiber

合併後,回到父節點Item,父節點標記完成。

2react中什麼是fiber

下一個工作單元是Item,在進入Item之前,檢查時間。但這時候時間就用完了。此時react必須交換主線程,並告訴主線程以後要為其分配時間以完成剩下的操作。

2react中什麼是fiber

主執行緒接下來進行放大字體的操作。完成後執行react接下來的操作,跟上一個Item的處理流程幾乎一樣,處理完成後整個fiber-tree和workInProgress如下:

2react中什麼是fiber

完成後,Item向List回傳並merge effect,effect List現在如下所示:

2react中什麼是fiber

#此時List向根節點返回並merge effect,所有節點都可以標記完成了。此時react將workInProgress標記為pendingCommit。意思是可以進入commit階段了。

2react中什麼是fiber

此時,要做的是還是檢查時間夠不夠用,如果沒有時間,會等到時間再去提交修改到DOM。進入階段2後,reacDOM會根據階段1計算出來的effect-list來更新DOM。

更新完DOM之後,workInProgress就完全和DOM保持一致了,為了讓當前的fiber-tree和DOM保持一直,react交換了current和workinProgress兩個指針。

2react中什麼是fiber

事實上,react大部分時間都在維持兩個樹(Double-buffering)。這可以縮減下次更新時,分配記憶體、垃圾清理的時間。 commit完成後,執行componentDidMount函式。

小結

透過將reconciliation過程,分解成小的工作單元的方式,可以讓頁面對於瀏覽器事件的回應更加及時。但是另一個問題還是沒有解決,就是如果目前在處理的react渲染耗時較長,仍然會阻塞後面的react渲染。這就是為什麼fiber reconciler增加了優先策略。

【相關推薦:Redis影片教學

#

以上是react中什麼是fiber的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn