計算機領域中有兩個你們很熟悉也很重要的概念:進程(Process)和線程(Thread),算法
進程:就是包換上下文切換的程序執行時間總和 = CPU加載上下文+CPU執行+CPU保存上下文,一個進程能夠有多個線程。 線程是共享了進程的上下文環境,的更爲細小的CPU時間段。線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位
可是在計算機科學中還有一個概念叫作Fiber,英文含義就是「纖維」,意指比Thread更細的線,也就是比線程(Thread)控制得更精密的併發處理機制。瀏覽器
React Fiber 並非所謂的纖程(微線程、協程),而是一種基於瀏覽器的單線程調度算法,背後的支持 API 是大名鼎鼎的:requestIdleCallback。併發
Fiberl是一種將 recocilation (遞歸 diff),拆分紅無數個小任務的算法;它隨時可以中止,恢復。中止恢復的時機取決於當前的一幀(16ms)內,還有沒有足夠的時間容許計算。函數
咱們都知道,React最引覺得豪的技術,可能就是虛擬DOM,經過虛擬DOM,能夠將原來十分耗時的DOM操做簡化,從而提升頁面性能。虛擬DOM的背後,須要的是一套快速對比(diff)出更新的算法。在React 16版本以前,React 經過遞歸比對新舊DOM樹來完成這個過程,而且這個過程是同步進行的。雖然React已經對這個diff算法作了不少優化,可是擋不住組件個數多啊。性能
因此,當多個組件(100個以上)同步進行更新操做的時候,瀏覽器將處於一種「假死」狀態,在這個狀態將沒法處理其餘事件,因此致使頁面卡頓等影響體驗的問題。優化
經過使用React fiber技術,優化了虛擬DOM的diff算法,同時也建立真實DOM和組件渲染拆分爲無數的小分片任務,每次執行完一個小分片後就冒泡看看有沒有優先級比較高的任務,有的話就去執行優先級比較高的任務,沒有就繼續執行下一個分片任務。this
上面咱們說的,React fiber 把建立真實DOM和組件渲染拆分紅小分片來輪訓執行,若是有新的優先級較高的任務,就先執行高優先級的任務,而後再來執行分片,這樣就會引發一個新的問題:一個更新任務尚未完成,就被另外一個更高優先級的更新過程打斷了怎麼辦? spa
這時候,優先級高的更新任務會優先處理完,而低優先級更新任務所作的工做則會徹底做廢,而後等待機會重頭再來。線程
由於一個更新過程可能被打斷,因此React Fiber一個更新過程被分爲兩個階段(Phase):第一個階段Reconciliation Phase和第二階段Commit Phase。code
在第一階段Reconciliation Phase,React Fiber會找出須要更新哪些DOM,這個階段是能夠被打斷的;可是到了第二階段Commit Phase,那就一氣呵成把DOM更新完,毫不會被打斷。
這兩個階段大部分工做都是React Fiber作,和咱們相關的也就是生命週期函數。
上面咱們說到,使用React Fiber技術後,生命週期函數可能在一次更新過程當中不止一次的被調用。
第一階段可能會調用下面這些生命週期函數,說是「可能會調用」是由於不一樣生命週期調用的函數不一樣。
componentWillMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate
下面這些生命週期函數則會在第二階段調用。
componentDidMount componentDidUpdate componentWillUnmount
經過以上分析咱們瞭解到,原來的React 生命週期函數中:
componentWillMount componentWillReceiveProps componentWillUpdate
這三個應該爲可能不止一次被調用,以前可能會有部分比較耗時的業務代碼(操做真是DOM)寫在這些函數裏,當不止一次調用這些函數的時候,可能會一塊兒很大的新能問題。
所以,React 16+ 引入了一個新的靜態生命週期函數 getDerivedStateFromProps 來將屬性從props中添加(同步)到state中,這是一個「靜態函數」,它不屬於任務一個實例,內部的 this並不指向組件自己,其實就是強迫把這個函數變成一個純函數
getSnapshotBeforeUpdate這個函數在 commit階段執行,咱們知道到commit階段後,這個函數只會執行一次,因此能夠在這裏完成那些必須的操做真實DOM的操做。