React Fiber學習小結

前天在油管上看了大神的一個關於js優化的分享,佩服的五體投地。可是視頻又過短了,就20來分鐘,有點意猶未盡的意思,還好視頻結尾放了幾篇大神寫的關於react fiber的文章,因此趕忙找來學習了一下。html

Fiber

fiber node是react內部用來表明一些須要完成的工做的一種數據結構,每個react element都會對應一個fiber node。以前react15裏的vdom tree如今就變成了一個fiber tree,每個fiber node都保存着指向其sibling, child 和 parent的指針。因此fiber tree大概就是一個雙向的linked list吧。node

爲啥搞fiber

既然已經有了vdom tree,爲啥又搞了這麼個fiber tree?react

我沒細讀過源碼,不過從官方文檔,大概由於vdom tree的遍歷採用了遞歸的寫法。 遞歸一旦開始,在結束以前,都不受控了。也就是說,若是react觸發一次update,那麼在update完成以前,瀏覽器主線程啥都幹不了。。 若是這個update耗時比較久,那就會形成卡頓。git

因此最大的問題就是遍歷起來不受控了。。想要控制咋辦?拿while來改寫遞歸唄。因此react組裏的大佬們就搞出了這麼個"fiber linked list"。github

fiber工做流程

fiber的工做大概能夠分爲兩個階段: 1. render 2. commit瀏覽器

render phase

在第一次mount以後,react會爲每個渲染的react element都創建一個fiber node,並組成一顆樹(current)。當更新觸發的時候,react會創建另一顆樹(workInProgress),全部的updates都會反映在這顆樹上。而且兩顆樹之間的節點都有一個alternate的屬性,指向本身在另外一顆樹上的映射。在這個階段,react會在workInProgress的節點上更新state和props,但並不會作任何帶有side effect的操做(留給commit階段),這裏react只會給每一個節點記錄在commit階段到底應該作些啥操做,這個信息保存在effectTag字段上。數據結構

除了構建workInProgress樹以外,爲了提升性能,react 還會維護一個effect list。就是用全部有sideeffect操做的節點構建一個linkedlist。 等真的到了要執行這些操做的時候,直接掃這個list就行了,而不用去遍歷整個樹。dom

除了上面的工做,render phase還會調用如下的函數:異步

  1. [UNSAFE_]componentWillMount (deprecated)
  2. [UNSAFE_]componentWillReceiveProps (deprecated)
  3. getDerivedStateFromProps
  4. shouldComponentUpdate
  5. [UNSAFE_]componentWillUpdate (deprecated)
  6. render

commit phase

render階段生成了current樹,workInProgress樹和effect list,接下來就進入到commit 階段。async

在commit階段,react會直接遍歷effect list,完成每一個節點的操做。在全部節點完成以後,用workInProgress樹來替換current樹,舊的current樹就能夠被垃圾回收了。

在commit階段,除了完成每一個節點的工做外,還會跑這幾個函數:

  1. 對於有snapShop標籤的node,調用getSnapshotBeforeUpdate
  2. 對於有Deletion標籤的node,調用componentWillUnmount
  3. 對於有Placement標籤的node,調用componentDidMount
  4. 對於有Update標籤的node,調用componentDidUpdate

那麼問題來了, 爲啥react要大費周章的搞這麼兩個階段呢?

緣由是在render phase階段,全部操做能夠是異步的。 react會把遍歷整顆樹的任務切成小任務,放在requestIdleCallback裏面來執行。 可是每次在暫停以後,下一次再繼續的時候,有可能會放棄掉以前作的全部任務重頭來過(這個的緣由不是特別清楚,多是在兩個任務以前,某個狀態改變了,以前的任務可能已經失效了?),因此全部會產生反作用的操做都不能放在這個階段執行。 react 16.3把不少原來經常使用的生命週期標記爲unsafe也是這個道理。就是由於react的大佬們發現使用者老在這些生命週期函數寫一些帶反作用的邏輯。這種寫法在fiber的體系下問題就很大(可能會被執行屢次), 官方的這篇文章把這個事情也說的特別清楚了。

而commit phase則相反,全部的操做都會一口氣作完(同步)。因此啊,在commit phase調用的生命週期裏面,最好仍是不要作過重的活爲好。。

參考文獻

React Fiber Architecture The how and why on React’s usage of linked list in Fiber to walk the component’s tree

Inside Fiber: in-depth overview of the new reconciliation algorithm in React

Update on Async Rendering

相關文章
相關標籤/搜索