Vue中的Diff算法

1. 為什么要用Diff算法

由于在瀏覽器中操作DOM的代價是非常“昂貴”的,所以才在Vue引入了Virtual DOM焰枢,Virtual DOM是對真實DOM的一種抽象描述钾埂,不懂的朋友可以自行查閱相關(guān)資料。

1.1為什么需要VD

VD 最大的特點是將頁面的狀態(tài)抽象為 JS 對象的形式腋寨,配合不同的渲染工具,使跨平臺渲染成為可能。如 React 就借助 VD 實現(xiàn)了服務(wù)端渲染拘鞋、瀏覽器渲染和移動端渲染等功能。

此外矢门,在進行頁面更新的時候盆色,借助VD,DOM 元素的改變可以在內(nèi)存中進行比較祟剔,再結(jié)合框架的事務(wù)機制將多次比較的結(jié)果合并后一次性更新到頁面隔躲,從而有效地減少頁面渲染的次數(shù),提高渲染效率物延。我們先來看下頁面的更新一般會經(jīng)過幾個階段宣旱。



從上面的例子中,可以看出頁面的呈現(xiàn)會分以下3個階段:

JS計算

生成渲染樹

繪制頁面

這個例子里面叛薯,JS計算用了691毫秒浑吟,生成渲染樹578毫秒,繪制73毫秒耗溜。如果能有效的減少生成渲染樹和繪制所花的時間组力,更新頁面的效率也會隨之提高。

通過VD的比較抖拴,我們可以將多個操作合并成一個批量的操作燎字,從而減少dom重排的次數(shù),進而縮短了生成渲染樹和繪制所花的時間城舞。至于如何基于VD更有效率的更新dom轩触,是一個很有趣的話題,日后有機會將另寫一篇文章介紹家夺。



即使使用了Virtual DOM來進行真實DOM的渲染脱柱,在頁面更新的時候,也不能全量地將整顆Virtual DOM進行渲染拉馋,而是去渲染改變的部分榨为,這時候就需要一個計算Virtual DOM樹改變部分的算法了惨好,這個算法就是Diff算法。


2. 傳統(tǒng)的Diff算法

傳統(tǒng)的Diff算法通過循環(huán)遞歸對節(jié)點進行比較随闺,然后判斷每個節(jié)點的狀態(tài)以及要做的操作(add日川,remove,change)矩乐,最后 根據(jù)Virtual DOM進行DOM的渲染龄句。大體流程如下圖(圖來源):


傳統(tǒng)Diff算法的復(fù)雜度為O(n^3),這個復(fù)雜度相對來說還是較高的散罕。后來React開發(fā)者提供了一種復(fù)雜度僅為O(n) 的Diff算法分歇。下面就來看一下O(n)復(fù)雜度的Diff算法是如何實現(xiàn)的。

3. 更高效的Diff算法

React的開發(fā)者結(jié)合Web界面的特點做出了兩個大膽的假設(shè)欧漱,使得Diff算法復(fù)雜度直接從O(n^3)降低到O(n)职抡,假設(shè)如下:

兩個相同組件產(chǎn)生類似的DOM結(jié)構(gòu),不同的組件產(chǎn)生不同的DOM結(jié)構(gòu)误甚;

對于同一層次的一組子節(jié)點缚甩,它們可以通過唯一的id進行區(qū)分。

通過這兩個假設(shè)窑邦,他們提供了下面的Diff算法思路擅威。

同層比較

新的Diff算法是逐層進行比較,只比較同一層次的節(jié)點奕翔,大大降低了復(fù)雜度裕寨,具體如下圖。在后面的內(nèi)容中也會介紹Vue中同層節(jié)點比較的具體實現(xiàn)派继。


不同類型節(jié)點的比較

如果發(fā)現(xiàn)新舊兩個節(jié)點類型不同時宾袜,Diff算法會直接刪除舊的節(jié)點及其子節(jié)點并插入新的節(jié)點,這是由于前面提出的不同組件產(chǎn)生的DOM結(jié)構(gòu)一般是不同的驾窟,所以可以不用浪費時間去比較庆猫。注意的是,刪除節(jié)點意味著徹底銷毀該節(jié)點绅络,并不會將該節(jié)點去與后面的節(jié)點相比較月培。

相同類型節(jié)點的比較

若是兩個節(jié)點類型相同時,Diff算法會更新節(jié)點的屬性實現(xiàn)轉(zhuǎn)換恩急。

列表節(jié)點的比較

列表節(jié)點的操作一般包括添加杉畜、刪除和排序,列表節(jié)點需要我們給它一個key才能進行高效的比較衷恭。

4.Vue Diff算法的實現(xiàn)

了解了Diff算法的大體思路后此叠,我們回過頭來看下Vue中的Diff算法是如何實現(xiàn)的。

Vue的Diff算法與上面的思路大體相似随珠,只比較同級的節(jié)點灭袁,若找不到與新節(jié)點類型相同的節(jié)點猬错,則插入一個新節(jié)點,若有相同類型的節(jié)點則進行節(jié)點屬性的更新茸歧,最后刪除新節(jié)點列表中不包含的舊節(jié)點倦炒。具體的實現(xiàn)在vue源碼的src/core/vdom/patch.js中的updateChildren方法中,由于代碼較長软瞎,下面簡單說一下整個的比較流程逢唤。


如上圖,有一組新舊節(jié)點數(shù)組before:[A, B, C, D]铜涉、after:[E, C, F, G]智玻,我們設(shè)置了四個哨兵節(jié)點,oldStartIdx芙代、newStartIdx、oldEndIdx盖彭、newEndIdx分別指向新舊節(jié)點數(shù)組的起始下標(biāo)和開始下標(biāo)纹烹,值為0,0,3,3;oldStartVnode召边,newStartVnode铺呵,oldEndVnode,newEndVnode則分別指向了before和after節(jié)點列表中對應(yīng)哨兵節(jié)點下標(biāo)的值隧熙,值為before[oldStartVnode],after[newStartIdx],before[oldEndIdx],after[newEndIdx]片挂。

總結(jié)

Vue中的Diff算法采用了React相似的思路,都是同層節(jié)點進行比較贞盯,在比較的過程中音念,使用了一些優(yōu)先判斷和就地復(fù)用策略,提高了Diff算法的效率躏敢。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闷愤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子件余,更是在濱河造成了極大的恐慌讥脐,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啼器,死亡現(xiàn)場離奇詭異旬渠,居然都是意外死亡,警方通過查閱死者的電腦和手機端壳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門告丢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人更哄,你說我怎么就攤上這事芋齿⌒瓤埽” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵觅捆,是天一觀的道長赦役。 經(jīng)常有香客問我,道長栅炒,這世上最難降的妖魔是什么掂摔? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮赢赊,結(jié)果婚禮上乙漓,老公的妹妹穿的比我還像新娘。我一直安慰自己释移,他們只是感情好叭披,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著玩讳,像睡著了一般涩蜘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熏纯,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天同诫,我揣著相機與錄音,去河邊找鬼樟澜。 笑死误窖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秩贰。 我是一名探鬼主播霹俺,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萍膛!你這毒婦竟也來了吭服?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝗罗,失蹤者是張志新(化名)和其女友劉穎艇棕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體串塑,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡沼琉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了桩匪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片打瘪。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闺骚,到底是詐尸還是另有隱情彩扔,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布僻爽,位于F島的核電站虫碉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胸梆。R本人自食惡果不足惜敦捧,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碰镜。 院中可真熱鬧兢卵,春花似錦、人聲如沸绪颖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菠发。三九已至王滤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滓鸠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工第喳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留糜俗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓曲饱,卻偏偏與公主長得像悠抹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子扩淀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容