Vue2.0引入了虛擬DOM,比Vue1.0的初始渲染速度提高了2~4倍,並大大下降了內存消耗。目前主流的前端框架Vue、React核心技術也都使用了虛擬DOM,你是否好奇爲何要提出虛擬DOM,虛擬DOM是什麼,它有什麼優點?這一切的問題,都將在本篇揭曉。前端
在Web早期,頁面的交互比較簡單,沒有複雜的狀態須要管理,也不太須要頻繁的操做DOM,隨着時代的發展,頁面上的功能愈來愈多,咱們須要實現的需求也愈來愈複雜,DOM的操做也愈來愈頻繁。經過js操做DOM的代價很高,由於會引發頁面的重排重繪,增長瀏覽器的性能開銷,下降頁面渲染速度,既然操做DOM的代價很高那麼有沒有那種方式能夠減小對DOM的操做?這就是爲何提出虛擬DOM一個很重要的緣由。node
Vue.js經過編譯將模版轉換成渲染函數(render),執行渲染函數就能夠獲得一個以vnode節點(JavaScript對象)做爲基礎的樹形結構,vnode節點裏麪包含標籤名(tag)、屬性(attrs)和子元素對象(children)等等屬性,這個樹形結構就是Virtual DOM,簡單來講,能夠把Virtual DOM理解爲一個樹形結構的JS對象。git
模板轉換成視圖的過程整個過程: github
咱們先對上圖幾個概念嵌入解釋:對於虛擬DOM,我們來看一個簡單的實例,就是下圖所示的這個,詳細的闡述了模板 → 渲染函數 → 虛擬DOM樹 → 真實DOM的一個過程 算法
傳統方式用js操做DOM會有不少額外的DOM操做,例如,一個ul標籤下有不少個li標籤,其中只有一個li有變化,這種狀況下若是使用新的ul去替代舊的ul,其實除了那個發生變化的li節點以外,其餘節點都不須要從新渲染。因爲DOM操做比較慢,因此這些DOM操做在性能上會有必定的浪費,避免這些沒必要要的DOM操做會提高很大一部分性能(減小重排重繪從而節省瀏覽器的性能開銷)。瀏覽器
爲了不沒必要要的DOM操做,虛擬DOM在虛擬節點映射到視圖的過程當中,將虛擬節點與上一次渲染視圖緩存的虛擬節點(oldVnode)作對比,找出真正須要更新的節點來進行DOM操做,從而避免操做其餘無任何改動的DOM。 其實虛擬DOM在Vue.js中主要作了兩件事:緩存
diff 算法包括幾個步驟:bash
diff 算法自己很是複雜,實現難度很大。本文去繁就簡,粗略介紹如下兩個核心函數實現流程:前端框架
經過這個函數可讓vnode渲染成真正的DOM,咱們經過如下模擬代碼,能夠了解大體過程:app
function createElement(vnode) {
var tag = vnode.tag
var attrs = vnode.attrs || {}
var children = vnode.children || []
if (!tag) {
return null
}
// 建立真實的 DOM 元素
var elem = document.createElement(tag)
// 屬性
var attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
// 給 elem 添加屬性
elem.setAttribute(attrName, attrs[attrName])
}
}
// 子元素
children.forEach(function (childVnode) {
// 給 elem 添加子元素,若是還有子節點,則遞歸的生成子節點。
elem.appendChild(createElement(childVnode)) // 遞歸
}) // 返回真實的 DOM 元素
return elem
}
複製代碼
這裏咱們只考慮vnode與newVnode如何對比的狀況:
function updateChildren(vnode, newVnode) {
var children = vnode.children || []
var newChildren = newVnode.children || []
// 遍歷現有的children
children.forEach(function (childVnode, index) {
var newChildVnode = newChildren[index]
// 二者tag同樣
if (childVnode.tag === newChildVnode.tag) {
// 深層次對比,遞歸
updateChildren(childVnode, newChildVnode)
} else {
// 二者tag不同
replaceNode(childVnode, newChildVnode)
}
}
)}
複製代碼
具有跨平臺的優點 因爲 Virtual DOM 是以 JavaScript 對象爲基礎而不依賴真實平臺環境,因此使它具備了跨平臺的能力,好比說瀏覽器平臺、Weex、Node 等。
操做 DOM 慢,js運行效率高。咱們能夠將DOM對比操做放在JS層,提升效率。 由於DOM操做的執行速度遠不如Javascript的運算速度快,所以,把大量的DOM操做搬運到Javascript中,運用patching算法來計算出真正須要更新的節點,最大限度地減小DOM操做,從而顯著提升性能。
提高渲染性能 Virtual DOM的優點不在於單次的操做,而是在大量、頻繁的數據更新下,可以對視圖進行合理、高效的更新。
總結:Vue.js經過編譯將模版轉換成渲染函數(render),執行渲染函數就能夠獲得一個虛擬節點樹(虛擬DOM),虛擬節點樹(虛擬DOM)提供虛擬節點vnode和對新舊兩個vnode進行比對並根據比對結果進行DOM操做來更新視圖,最大限度減小對DOM操做,從而減小瀏覽器的開銷,提升渲染速度,改善用戶體驗。
參考文章: github.com/ljianshu/Bl…