虛擬dom和diff算法


https://github.com/livoras/blog/issues/13

這里簡單記錄一些要點和理解:

  一個dom元素中有許多屬性,操作dom是很耗資源的,而操作自定義的js對象是很高效。所以在操作dom之間多加一層“虛擬dom”,建立虛擬dom與dom的關聯,把直接操作dom轉換為操作虛擬dom,然后把最終的虛擬dom關聯到dom上,關聯的方式是把差異應用到dom上。

  一個js對象來描述一個dom,只需要tagName、props以及children即可。

一個虛擬dom應用,有如下初始化過程

  1. 通過js(如react的jsx)確定好虛擬dom
  2. 根據虛擬dom生成實際的dom樹,寫到body中  

在js中對虛擬dom進行操作,每次操作會生成一顆新的虛擬dom樹,虛擬dom的新樹和舊樹進行對比,找出差異,然后這些差異會被應用到實際的dom上,完成界面的變更。

對比方式:

  同層次節點對比,深度優先。

差異的類型以及處理方式

  1. 標簽名變更,則整個節點統一進行替換,里面的子節點也跟着替換。
  2. 標簽的屬性變更,把變更的屬性應用上去。
  3. 文本節點內容變更,直接替換即可。
  4. 子元素個體的增加、刪除、移動。

如何檢測子元素個體的變更?

  為每個個體都加上一個標識符key,在當前兄弟節點中這個key要唯一,這樣才能在當前的所有children中唯一標識。標識完成后,問題就可以轉化為字符串的對比問題了,這里對比只能得出列表的差異(增加刪除移動等)。接着繼續進行相同key的節點的對比,到這里可見差異的對比是遞歸的。進行子元素個體的標識,有利於dom的復用,如果不指定,算法會認為兩個子元素列表完全不一樣,會全部重新渲染,這就很耗費性能了。

“如果元素沒有重排,使用數組的索引作為key效果不錯”。如何理解這句話呢?

  沒重排的意思是,結構體的展示次序不發生變化,而僅僅是結構體中少量屬性發生變更。在這種情況下,兩個列表元素依次一一對應,找出差異,然后把這些差異按次序應用到列表dom上。如果元素有重排,而且使用了索引作為key,兩個列表中相同索引的結構體會完全不同,這樣一進行對比,可能會得出一大堆的差異,再將這些差異應用上去可能會比較慢,我感覺其實這些說的都只是相對而已。

如何把差異應用(patch)到實際dom上?

  最開始初始化的時候,根據虛擬dom生成實際的dom,兩者的結構層次是一樣的,而差異是通過對虛擬dom深度優先對比出來的,應用當然是對實際dom進行深度優先,然后把差異應用上去。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM