Virtual Dom Diff原理,極簡版

2021-09-11 21:21:02 字數 2652 閱讀 5167

先介紹乙個概念virtual dom,我猜大家或多或少都應該知道什麼是virtual dom吧,簡單來說就是用js來模擬dom中的結點。

下面就是乙個virtual dom的結構,包含了標籤名,擁有的屬性,孩子結點,render函式

class element ;

this.children = children || ;

} render

() }複製**

建立一棵個virtual dom tree && 渲染
/**

**///根據上面結構可以用一下方式建立一棵 virtual dom tree

let ul = element('ul', , [

element('li', , ['txt_a']),

element('li', , ['txt_b'])

]);//ul 就是一棵個virtual dom tree

let uldom = ul.render();//生成真實dom

複製**

以上就是virtual dom tree如何被轉換成真實dom並新增到網頁中的過程,再這個過程中我把render函式給省略,只是為了讓你們先了解原理,具體實現可以以後再深究。我學乙個東西的時候,習慣是先把整體原理弄清楚,再去深入學習相關的知識。

在介紹diff演算法之前,再次宣告我只會列舉diff演算法中會用到的函式,並串聯它們之間的關係並不會給出具體實現的**

介紹diff演算法是進行虛擬節點element的對比,並返回乙個pathchs物件,用來儲存兩個節點不同的地方,最後用pathchs記錄的訊息去區域性更新dom。

兩個樹如果完全比較的話需要時間複雜度為o(n^3),如果對o(n^3)不太清楚的話建議去網上搜尋資料。而在diff演算法中因為考慮效率的問題,只會對同層級元素比較,時間複雜度則為o(n),說白了就是深度遍歷,並比較同層級的節點。

diff只需下面兩句**

let pathchs = diff(oldtree, newtree);//獲取兩棵virtual dom tree 差異

patch(uldom, pathchs);//找到對應的真實dom,進行部分渲染

複製**

diff中所用到的函式
//深度遍歷樹,將需要做變更操作的取出來

//區域性更新 dom

function patch(node,pathchs)

// diff 入口,比較新舊兩棵樹的差異

function diff (oldtree, newtree) // 記錄每個節點差異的補丁

dfs(oldtree, newtree, index, patches)

return patches;

}/**

* dfs 深度遍歷查詢節點差異

* @param oldnode - 舊虛擬dom樹

* @param newnode - 新虛擬dom樹

* @param index - 當前所在樹的第幾層

* @param patches - 記錄節點差異

*/function dfs (oldnode, newnode, index, patches)else

if (istxt(oldnode) && istxt(newnode)) )

//如果發現文字不同,currentpatch會記錄乙個差異

}else

if(oldnode.tagname === newnode.tagname && oldnode.key === newnode.key))

}// 遞迴遍歷子節點,並對子節點進行diff比較

diffchildren(oldnode.children, newnode.children, index, patches)

}else)

}//如果有差異則記錄到當前層去

if (currentpatch.length) else

}}//判斷兩個節點的屬性差異

function diffattrs(oldnode, newnode);//記錄差異

let count = 0;//記錄差異的條數

/****略

判斷兩個節點的屬性差異的**就略了,

讓你們知道這裡的**就是判斷兩個節點的屬性有哪些差異,

如果有差異就記錄在attrspatches這個物件中,並把它返回

**/if(0 == count)else

}//判斷孩子節點

function diffchildren(oldchild, newchild, index, patches) = listdiff(oldchild, newchild, index, patches);

if (changes.length) else

}// **略

//遍歷當前陣列

oldchild && oldchild.foreach((item, i) => )

}//判斷oldnodelist, newnodelist 節點的位置差,主要是為了判斷哪些節點被移動、刪除、新增。

function listdiff(oldnodelist, newnodelist, index);

}複製**

如果大家對函式之間的呼叫還不明白的話可以看下面的圖

virtual dom 演算法的實現也就是以下三步

原環套原環

今天在除錯兄弟的程式的時候發現了乙個問題,就是在組合資料的時候,有些時候可以成功,有些時候失敗,感覺十分奇怪。功能大概是這樣的,就是在一棵樹上掛資料,所有的節點都可以有資料,不只是葉子的,在組合資料的時候,可以從任意節點取資料,但是不能是重複的資料。資料可能出現的情況如圖a b c所示,圖a是沒有干...

MongoDB writeConcern原理解析

mongodb支援客戶端靈活配置寫入策略 writeconcern 以滿足不同場景的需求。db.collection.insert mongodb支援的writeconncern選項如下 w 資料寫入到number個節點才向用客戶端確認 j 寫入操作的journal持久化後才向客戶端確認 wtime...

LinkedBlockingQueue原理分析

linkedblockingqueue也是乙個阻塞佇列,相比於arrayblockingqueue,他的底層是使用鍊錶實現的,而且是乙個可有界可無界的佇列,在生產和消費的時候使用了兩把鎖,提高併發,是乙個高效的阻塞佇列,下面就分析一下這個佇列的原始碼。鍊錶節點定義 static class node...