React Diff演算法一覽
前言
diff演算法一直是React系統最核心的部分,並且由於演化自傳統diff,使得比較方式從O(n^3)降級到O(n),然後又改成了連結串列方式,可謂是變化萬千。
傳統Diff演算法
傳統diff演算法需要迴圈比較兩棵樹,所有節點的迴圈,那麼單純比較次數就是O(n^2),n*n
P L A A / \ / \ / \ / \ B D ====> D B / \ C C
刷刷刷,每次都需要迴圈遍歷,於是有以下的查詢過程:
PA->LA
PA->LB
PA->LC
PA->LD
PB->LA
...
除了查詢過程消耗了O(n^2)之外,找到差異後還要計算最小轉換方式,最終結果為O(n^3)。
所以,傳統的diff演算法的時間複雜度為O(n^3)。
如果React運用這種演算法,那麼節點過多,將會有大量的開銷,雖然CPU的秒速達到30億次計算,但依舊是非常耗費效能的。
有沒有什麼方式可以降低時間複雜度呢?
於是,React15對傳統的diff做了一些限制,使得時間複雜度變為了O(n)。
React 15的Diff演算法
《深入React技術棧》這本書,給出了三種Diff策略分析,文字描述太過抽象,直接表述如下:
Tree diff、Component diff、Element diff
Tree diff
什麼是Tree diff?先上圖:
首先,進行同級比較,並非迴圈比較。這樣比較次數就降為一層一次,時間複雜度直接降為O(n)
如果同級相同位置節點不一樣,則直接刪除替換,簡單粗暴。
而對於節點移動,同樣道理,也是簡單粗暴的刪除重建。如下圖所示(圖中第四步應該是刪除左側的整棵A樹):
Component diff
不多說,先上圖:
其實component diff相當於是子樹的diff,基本方案和tree diff是一致的,如果如上圖D變為G,那麼直接刪除D這一整棵樹,然後重新渲染G樹。
依舊是簡單粗暴。
Element diff
對於同一節點的元素,diff演算法提供了三種操作:插入、移動、刪除。還是先上圖:
此時的操作,是B、D不做任何操作,AC移動到相應位置【前提是都有相同的key】
如果,此時的key不相同,全都發生了變化,那麼節點全都是要刪除重新構建,將會消耗大量效能。
React 16的Diff演算法
React16相比React15的Diff演算法發生了很大的變化,其中最主要就是引入了Fiber迴圈任務排程演算法。
Fiber
Fiber是什麼?幹了什麼?
Fiber在diff階段,做了如下的操作:
1、可以隨時將diff操作進行任務拆分。
2、diff階段的每個任務可以隨時執行或者中止。
3、diff階段任務排程優先順序控制。
所以,Fiber相當於是,在15的diff演算法階段,做了優先順序的任務排程控制,
所以,Fiber是根據一個fiber節點(VDOM節點)來拆分,以fiber node為一個任務單元,一 個元件例項都是一個任務單元。任務迴圈中,每處理完一個fiber node,可以中斷/掛起/恢復。
它又是如何能夠進行這樣的非同步操作的呢?這就不得不說一個方法:requestIdleCallback
瀏覽器提供的requestIdleCallback API中的Cooperative Scheduling可以讓瀏覽器在空閒時間執行回撥(開發者傳入的方法),在回撥引數中可以獲取到當前幀(16ms)剩餘的時間。利用這個資訊可以合理的安排當前幀需要做的事情,如果時間足夠,那繼續做下一個任務,如果時間不夠就歇一歇,呼叫requestIdleCallback來獲知主執行緒不忙的時候,再繼續做任務
Fiber Node是什麼?
連結串列!
將要處理的節點,存在連結串列結構,那麼就能夠做到節點複用。【這大概是Fiber的核心吧】
大體上的Diff引入了Fiber之後,我們就增加了更多的連結串列複用功能,通過這一點,我們可以使得React Diff的效能得到提升。
總結
其實,這篇文章著重講的還是React15的diff,React 16的diff並未詳細探討,接下來會出一篇文章,單獨講解React 16的Diff策略。不過React 16Diff策略的核心Fiber是不可錯過的點。
參考資料
《深入React技術棧》
https://segmentfault.com/a/1190000016723305
https://www.jianshu.com/p/3ba0822018cf
https://www.jianshu.com/p/21a445066d51?from=timeline
https://www.zhihu.com/question/66851503/answer/246766239
https://blog.csdn.net/P6P7qsW6ua47A2Sb/article/details/82322033
https://blog.csdn.net/VhWfR2u02Q/article/details/100011830
我的部落格:http://www.gaoyunjiao.fun/?p