久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

一篇文章帶你搞懂Vue虛擬Dom與diff算法

瀏覽:122日期:2022-12-03 14:04:41

前言

使用過Vue和React的小伙伴肯定對虛擬Dom和diff算法很熟悉,它扮演著很重要的角色。由于小編接觸Vue比較多,React只是淺學(xué),所以本篇主要針對Vue來展開介紹,帶你一步一步搞懂它。

虛擬DOM

什么是虛擬DOM?

虛擬DOM(Virtual Dom),也就是我們常說的虛擬節(jié)點,是用JS對象來模擬真實DOM中的節(jié)點,該對象包含了真實DOM的結(jié)構(gòu)及其屬性,用于對比虛擬DOM和真實DOM的差異,從而進(jìn)行局部渲染來達(dá)到優(yōu)化性能的目的。真實的元素節(jié)點:

<div id='wrap'> <p class='title'>Hello world!</p></div>

VNode:

{ tag:’div’, attrs:{ id:’wrap’ }, children:[ { tag:’p’, text:’Hello world!’, attrs:{ class:’title’, } } ]}

為什么使用虛擬DOM?

簡單了解虛擬DOM后,是不是有小伙伴會問:Vue和React框架中為什么會用到它呢?好問題!那來解決下小伙伴的疑問。起初我們在使用JS/JQuery時,不可避免的會大量操作DOM,而DOM的變化又會引發(fā)回流或重繪,從而降低頁面渲染性能。那么怎樣來減少對DOM的操作呢?此時虛擬DOM應(yīng)用而生,所以虛擬DOM出現(xiàn)的主要目的就是為了減少頻繁操作DOM而引起回流重繪所引發(fā)的性能問題的!

虛擬DOM的作用是什么?

兼容性好。因為Vnode本質(zhì)是JS對象,所以不管Node還是瀏覽器環(huán)境,都可以操作; 減少了對Dom的操作。頁面中的數(shù)據(jù)和狀態(tài)變化,都通過Vnode對比,只需要在比對完之后更新DOM,不需要頻繁操作,提高了頁面性能;

虛擬DOM和真實DOM的區(qū)別?

說到這里,那么虛擬DOM和真實DOM的區(qū)別是什么呢?總結(jié)大概如下:

虛擬DOM不會進(jìn)行回流和重繪; 真實DOM在頻繁操作時引發(fā)的回流重繪導(dǎo)致性能很低; 虛擬DOM頻繁修改,然后一次性對比差異并修改真實DOM,最后進(jìn)行依次回流重繪,減少了真實DOM中多次回流重繪引起的性能損耗; 虛擬DOM有效降低大面積的重繪與排版,因為是和真實DOM對比,更新差異部分,所以只渲染局部;

總損耗 = 真實DOM增刪改 + (多節(jié)點)回流/重繪; //計算使用真實DOM的損耗總損耗 = 虛擬DOM增刪改 + (diff對比)真實DOM差異化增刪改 + (較少節(jié)點)回流/重繪; //計算使用虛擬DOM的損耗

可以發(fā)現(xiàn),都是圍繞頻繁操作真實DOM引起回流重繪,導(dǎo)致頁面性能損耗來說的。不過框架也不一定非要使用虛擬DOM,關(guān)鍵在于看是否頻繁操作會引起大面積的DOM操作。

那么虛擬DOM究竟通過什么方式來減少了頁面中頻繁操作DOM呢?這就不得不去了解DOM Diff算法了。

DIFF算法

當(dāng)數(shù)據(jù)變化時,vue如何來更新視圖的?其實很簡單,一開始會根據(jù)真實DOM生成虛擬DOM,當(dāng)虛擬DOM某個節(jié)點的數(shù)據(jù)改變后會生成一個新的Vnode,然后VNode和oldVnode對比,把不同的地方修改在真實DOM上,最后再使得oldVnode的值為Vnode。

diff過程就是調(diào)用patch函數(shù),比較新老節(jié)點,一邊比較一邊給真實DOM打補丁(patch);

對照vue源碼來解析一下,貼出核心代碼,旨在簡單明了講述清楚,不然小編自己看著都頭大了O(∩_∩)O

patch

那么patch是怎樣打補丁的?

//patch函數(shù) oldVnode:老節(jié)點 vnode:新節(jié)點function patch (oldVnode, vnode) { ... if (sameVnode(oldVnode, vnode)) { patchVnode(oldVnode, vnode) //如果新老節(jié)點是同一節(jié)點,那么進(jìn)一步通過patchVnode來比較子節(jié)點 } else { /* -----否則新節(jié)點直接替換老節(jié)點----- */ const oEl = oldVnode.el // 當(dāng)前oldVnode對應(yīng)的真實元素節(jié)點 let parentEle = api.parentNode(oEl) // 父元素 createEle(vnode) // 根據(jù)Vnode生成新元素 if (parentEle !== null) { api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) // 將新元素添加進(jìn)父元素 api.removeChild(parentEle, oldVnode.el) // 移除以前的舊元素節(jié)點 oldVnode = null } } ... return vnode}//判斷兩節(jié)點是否為同一節(jié)點function sameVnode (a, b) { return ( a.key === b.key && // key值 a.tag === b.tag && // 標(biāo)簽名 a.isComment === b.isComment && // 是否為注釋節(jié)點 // 是否都定義了data,data包含一些具體信息,例如onclick , style isDef(a.data) === isDef(b.data) && sameInputType(a, b) // 當(dāng)標(biāo)簽是<input>的時候,type必須相同 )}

從上面可以看出,patch函數(shù)是通過判斷新老節(jié)點是否為同一節(jié)點:

如果是同一節(jié)點,執(zhí)行patchVnode進(jìn)行子節(jié)點比較; 如果不是同一節(jié)點,新節(jié)點直接替換老節(jié)點;

那如果不是同一節(jié)點,但是它們子節(jié)點一樣怎么辦嘞?OMG,要牢記:diff是同層比較,不存在跨級比較的!簡單提一嘴,React中也是如此,它們只是針對同一層的節(jié)點進(jìn)行比較。

patchVnode

既然到了patchVnode方法,說明新老節(jié)點為同一節(jié)點,那么這個方法做了什么處理?

function patchVnode (oldVnode, vnode) { const el = vnode.el = oldVnode.el //找到對應(yīng)的真實DOM let i, oldCh = oldVnode.children, ch = vnode.children if (oldVnode === vnode) return //如果新老節(jié)點相同,直接返回 if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) { //如果新老節(jié)點都有文本節(jié)點且不相等,那么新節(jié)點的文本節(jié)點替換老節(jié)點的文本節(jié)點 api.setTextContent(el, vnode.text) }else { updateEle(el, vnode, oldVnode) if (oldCh && ch && oldCh !== ch) { //如果新老節(jié)點都有子節(jié)點,執(zhí)行updateChildren比較子節(jié)點[很重要也很復(fù)雜,下面展開介紹] updateChildren(el, oldCh, ch) }else if (ch){ //如果新節(jié)點有子節(jié)點而老節(jié)點沒有子節(jié)點,那么將新節(jié)點的子節(jié)點添加到老節(jié)點上 createEle(vnode) }else if (oldCh){ //如果新節(jié)點沒有子節(jié)點而老節(jié)點有子節(jié)點,那么刪除老節(jié)點的子節(jié)點 api.removeChildren(el) } }}

如果兩個節(jié)點不一樣,直接用新節(jié)點替換老節(jié)點;

如果兩個節(jié)點一樣,

​新老節(jié)點一樣,直接返回; ​老節(jié)點有子節(jié)點,新節(jié)點沒有:刪除老節(jié)點的子節(jié)點; 老節(jié)點沒有子節(jié)點,新節(jié)點有子節(jié)點:新節(jié)點的子節(jié)點直接append到老節(jié)點; ​都只有文本節(jié)點:直接用新節(jié)點的文本節(jié)點替換老的文本節(jié)點; ​都有子節(jié)點:updateChildren

最復(fù)雜的情況也就是新老節(jié)點都有子節(jié)點,那么updateChildren是如何來處理這一問題的,該方法也是diff算法的核心,下面我們來了解一下!

updateChildren

由于代碼太多了,這里先做個概述。updateChildren方法的核心:

提取出新老節(jié)點的子節(jié)點:新節(jié)點子節(jié)點ch和老節(jié)點子節(jié)點oldCh; ch和oldCh分別設(shè)置StartIdx(指向頭)和EndIdx(指向尾)變量,它們兩兩比較(按照sameNode方法),有四種方式來比較。如果4種方式都沒有匹配成功,如果設(shè)置了key就通過key進(jìn)行比較,在比較過程種startIdx++,endIdx--,一旦StartIdx > EndIdx表明ch或者oldCh至少有一個已經(jīng)遍歷完成,此時就會結(jié)束比較。

下面結(jié)合圖來理解:

一篇文章帶你搞懂Vue虛擬Dom與diff算法

第一步:

oldStartIdx = A , oldEndIdx = C;newStartIdx = A , newEndIdx = D;

此時oldStartIdx和newStarIdx匹配,所以將dom中的A節(jié)點放到第一個位置,此時A已經(jīng)在第一個位置,所以不做處理,此時真實DOM順序:A B C;

第二步:

oldStartIdx = B , oldEndIdx = C;newStartIdx = C , oldEndIdx = D;

一篇文章帶你搞懂Vue虛擬Dom與diff算法

此時oldEndIdx和newStartIdx匹配,將原本的C節(jié)點移動到A后面,此時真實DOM順序:A C B;

第三步:

oldStartIdx = C , oldEndIdx = C;newStartIdx = B , newEndIdx = D;oldStartIdx++,oldEndIdx--;oldStartIdx > oldEndIdx

此時遍歷結(jié)束,oldCh已經(jīng)遍歷完,那么將剩余的ch節(jié)點根據(jù)自己的index插入到真實DOM中即可,此時真實DOM順序:A C B D;

所以匹配過程中判斷結(jié)束有兩個條件:

oldStartIdx > oldEndIdx表示oldCh先遍歷完成,如果ch有剩余節(jié)點就根據(jù)對應(yīng)index添加到真實DOM中; newStartIdx > newEndIdx表示ch先遍歷完成,那么就要在真實DOM中將多余節(jié)點刪除掉;

看下圖這個實例,就是新節(jié)點先遍歷完成刪除多余節(jié)點:

一篇文章帶你搞懂Vue虛擬Dom與diff算法

最后,在這些子節(jié)點sameVnode后如果滿足條件繼續(xù)執(zhí)行patchVnode,層層遞歸,直到oldVnode和Vnode中所有子節(jié)點都比對完成,也就把所有的補丁都打好了,此時更新到視圖。

總結(jié)

最后,用一張圖來記憶整個Diff過程,希望你能有所收獲!

一篇文章帶你搞懂Vue虛擬Dom與diff算法

彩蛋

因為React只是簡單學(xué)了基礎(chǔ),這里作為對比來概述一下:

1.React渲染機(jī)制:React采用虛擬DOM,在每次屬性和狀態(tài)發(fā)生變化時,render函數(shù)會返回不同的元素樹,然后對比返回的元素樹和上次渲染樹的差異并對差異部分進(jìn)行更新,最后渲染為真實DOM。

2.diff永遠(yuǎn)都是同層比較,如果節(jié)點類型不同,直接用新的替換舊的。如果節(jié)點類型相同,就比較他們的子節(jié)點,依次類推。通常元素上綁定的key值就是用來比較節(jié)點的,所以一定要保證其唯一性,一般不采用數(shù)組下標(biāo)來作為key值,因為當(dāng)數(shù)組元素發(fā)生變化時index會有所改動。

3.渲染機(jī)制的整個過程包含了更新操作,將虛擬DOM轉(zhuǎn)換為真實DOM,所以整個渲染過程就是Reconciliation。而這個過程的核心又主要是diff算法,利用的是生命周期shouldComponentUpdate函數(shù)。

到此這篇帶你搞懂Vue虛擬Dom與diff算法的文章就介紹到這了,更多相關(guān)Vue虛擬Dom與diff算法內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 欧美一区二区三区视频 | 午夜av电影 | 成人在线手机版视频 | 国产在线精品一区二区 | 一区二区在线看 | 久草精品在线 | 一区二区影院 | 春色av| 一区自拍| 国产第一区二区三区 | 亚洲精彩视频 | 亚洲欧美精品 | 日韩一片| 久久久久久精 | 成人精品鲁一区一区二区 | 日韩精品免费 | 国产一区二 | 日韩精品一区二区三区四区视频 | 伊人av超碰久久久麻豆 | 日韩精品在线免费观看视频 | 国产日韩欧美视频 | 欧美在线观看视频 | 久久成人在线 | 波多野结衣一区二 | 日韩欧美在线免费观看 | 中文字幕在线观看av | 91精品久久久久久 | 日韩成人在线一区 | 亚洲高清在线 | 久久美女| 国产97碰免费视频 | 国产xvideos免费视频播放 | 中文字幕av一区 | 蜜桃视频网站在线观看 | av网址在线播放 | 天天干国产 | 午夜精品久久 | 天天爽夜夜春 | 一区国产视频 | 91精品久久久久久久久中文字幕 | 国产精品69毛片高清亚洲 |