成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

virtualDom的DIFF算法關(guān)鍵過程整理

hot_pot_Leo / 2841人閱讀

摘要:,文本節(jié)點(diǎn)的比較,需要修改,則會(huì)調(diào)用。兩個(gè)節(jié)點(diǎn)都有子節(jié)點(diǎn),而且它們不一樣,這樣我們會(huì)調(diào)用函數(shù)比較子節(jié)點(diǎn),這是的核心。,新節(jié)點(diǎn)沒有子節(jié)點(diǎn),老節(jié)點(diǎn)有子節(jié)點(diǎn),直接刪除老節(jié)點(diǎn)。參考文章解析的算法

判斷對(duì)應(yīng)節(jié)點(diǎn)是否有必要進(jìn)行比較(sameVnode)
function sameVnode(oldVnode, vnode){
    return vnode.key === oldVnode.key && vnode.sel === oldVnode.sel
}

如果值得比較會(huì)執(zhí)行patchVnode(oldVnode, vnode)

如果不值得比較,新節(jié)點(diǎn)直接把老節(jié)點(diǎn)整個(gè)替換了

打補(bǔ)丁(patchVnode)
patchVnode (oldVnode, vnode) {
    const el = vnode.el = oldVnode.el
    let i, oldCh = oldVnode.children, ch = vnode.children
    if (oldVnode === vnode) return
    if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) {
        api.setTextContent(el, vnode.text)
    }else {
        updateEle(el, vnode, oldVnode)
        if (oldCh && ch && oldCh !== ch) {
            updateChildren(el, oldCh, ch)
        }else if (ch){
            createEle(vnode) //create el"s children dom
        }else if (oldCh){
            api.removeChildren(el)
        }
    }
}

節(jié)點(diǎn)的比較有5種情況

if (oldVnode === vnode),他們的引用一致,可以認(rèn)為沒有變化。

if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本節(jié)點(diǎn)的比較,需要修改,則會(huì)調(diào)用Node.textContent = vnode.text。

if( oldCh && ch && oldCh !== ch ), 兩個(gè)節(jié)點(diǎn)都有子節(jié)點(diǎn),而且它們不一樣,這樣我們會(huì)調(diào)用updateChildren函數(shù)比較子節(jié)點(diǎn),這是diff的核心。

else if (ch),只有新的節(jié)點(diǎn)有子節(jié)點(diǎn),調(diào)用createEle(vnode),vnode.el已經(jīng)引用了老的dom節(jié)點(diǎn),createEle函數(shù)會(huì)在老dom節(jié)點(diǎn)上添加子節(jié)點(diǎn)。

else if (oldCh),新節(jié)點(diǎn)沒有子節(jié)點(diǎn),老節(jié)點(diǎn)有子節(jié)點(diǎn),直接刪除老節(jié)點(diǎn)。

更新子節(jié)點(diǎn)(updateChildren)
updateChildren (parentElm, oldCh, newCh) {
    let oldStartIdx = 0, newStartIdx = 0
    let oldEndIdx = oldCh.length - 1
    let oldStartVnode = oldCh[0]
    let oldEndVnode = oldCh[oldEndIdx]
    let newEndIdx = newCh.length - 1
    let newStartVnode = newCh[0]
    let newEndVnode = newCh[newEndIdx]
    let oldKeyToIdx
    let idxInOld
    let elmToMove
    let before
    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
            if (oldStartVnode == null) {   //對(duì)于vnode.key的比較,會(huì)把oldVnode = null
                oldStartVnode = oldCh[++oldStartIdx] 
            }else if (oldEndVnode == null) {
                oldEndVnode = oldCh[--oldEndIdx]
            }else if (newStartVnode == null) {
                newStartVnode = newCh[++newStartIdx]
            }else if (newEndVnode == null) {
                newEndVnode = newCh[--newEndIdx]
            }else if (sameVnode(oldStartVnode, newStartVnode)) {
                patchVnode(oldStartVnode, newStartVnode)
                oldStartVnode = oldCh[++oldStartIdx]
                newStartVnode = newCh[++newStartIdx]
            }else if (sameVnode(oldEndVnode, newEndVnode)) {
                patchVnode(oldEndVnode, newEndVnode)
                oldEndVnode = oldCh[--oldEndIdx]
                newEndVnode = newCh[--newEndIdx]
            }else if (sameVnode(oldStartVnode, newEndVnode)) {
                patchVnode(oldStartVnode, newEndVnode)
                api.insertBefore(parentElm, oldStartVnode.el, api.nextSibling(oldEndVnode.el))
                oldStartVnode = oldCh[++oldStartIdx]
                newEndVnode = newCh[--newEndIdx]
            }else if (sameVnode(oldEndVnode, newStartVnode)) {
                patchVnode(oldEndVnode, newStartVnode)
                api.insertBefore(parentElm, oldEndVnode.el, oldStartVnode.el)
                oldEndVnode = oldCh[--oldEndIdx]
                newStartVnode = newCh[++newStartIdx]
            }else {
               // 使用key時(shí)的比較
                if (oldKeyToIdx === undefined) {
                    oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) // 有key生成index表
                }
                idxInOld = oldKeyToIdx[newStartVnode.key]
                if (!idxInOld) {
                    api.insertBefore(parentElm, createEle(newStartVnode).el, oldStartVnode.el)
                    newStartVnode = newCh[++newStartIdx]
                }
                else {
                    elmToMove = oldCh[idxInOld]
                    if (elmToMove.sel !== newStartVnode.sel) {
                        api.insertBefore(parentElm, createEle(newStartVnode).el, oldStartVnode.el)
                    }else {
                        patchVnode(elmToMove, newStartVnode)
                        oldCh[idxInOld] = null
                        api.insertBefore(parentElm, elmToMove.el, oldStartVnode.el)
                    }
                    newStartVnode = newCh[++newStartIdx]
                }
            }
        }
        if (oldStartIdx > oldEndIdx) {
            before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].el
            addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx)
        }else if (newStartIdx > newEndIdx) {
            removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
        }
}

主要的思路大概就是,定義變量,分別記錄當(dāng)前比較的新、舊節(jié)點(diǎn)中的首尾索引與節(jié)點(diǎn)(oldStartVnode、oldEndVnode、newStartVnode、newEndVnode)(后續(xù)稱為比較區(qū)間)

(圖片來自:https://github.com/aooy/blog/... )

通過對(duì) oldStartVnode、oldEndVnode、newStartVnode、newEndVnode 做,兩兩的 sameVnode 比較

比較判斷有4種,按順序依次比較
oldStartVnode —— newStartVnode (頭對(duì)頭)
oldEndVnode —— newEndVnode (尾對(duì)尾)
oldStartVnode —— newEndVnode (頭對(duì)尾)
oldEndVnode —— newStartVnode (尾對(duì)頭)

如果其中一種比較成立了,那么oldVode中的相應(yīng)節(jié)點(diǎn)會(huì) 以當(dāng)前比較區(qū)間為基準(zhǔn) 移到newVnode相應(yīng)的位置上,
然后比較區(qū)間會(huì)根據(jù)當(dāng)前的比較條件類型,以頭或尾為縮小比較區(qū)間的方向,縮小區(qū)間

例如: 當(dāng)oldStartVnode,newEndVnode值得比較時(shí), 將oldStartVnode.el移動(dòng)到oldEndVnode.el后邊

當(dāng)4種比較都不成立時(shí),會(huì)使用key去比較,并在最終都使newVode的比較區(qū)間,頭部 減1

當(dāng)oldVnode的key列表中能匹配到對(duì)應(yīng)的key時(shí),判斷比較節(jié)點(diǎn)的選擇器屬性是否一樣

不一樣則直接在當(dāng)前比較區(qū)間的頭部,新創(chuàng)建一個(gè)newVnode的Dom插入

比較節(jié)點(diǎn)中的oldVnode無需處理,因?yàn)楹竺娴谋容^中不會(huì)有成立的比較條件,最終會(huì)直接刪除節(jié)點(diǎn)

如果一樣則將比較節(jié)點(diǎn)中的oldVnode移動(dòng)到當(dāng)前比較區(qū)間的頭部(所以為節(jié)點(diǎn)設(shè)置key可以更高效的利用dom),并將比較區(qū)間中oldVnode原本的索引位置賦值為Null

如果最終key列表也沒能匹配到的話,也是直接在當(dāng)前比較區(qū)間的頭部,新創(chuàng)建一個(gè)newVnode的Dom插入。

最后在結(jié)束時(shí)會(huì)存在2種情況

oldStartIdx > oldEndIdx

oldVnode先遍歷完,證明newVode有新增的節(jié)點(diǎn),或者一致,這種情況會(huì)將newVode剩余的節(jié)點(diǎn)插入到oldVnode比較區(qū)間的末尾

newStartIdx > newEndIdx

這時(shí)是newVode先遍歷完,證明newVode里刪除了某些節(jié)點(diǎn),此時(shí)oldVnode的比較區(qū)間節(jié)點(diǎn)是已經(jīng)不存在的,會(huì)將他們刪除。

參考文章:解析vue2.0的diff算法

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103068.html

相關(guān)文章

  • React系列 --- virtualdom diff算法實(shí)現(xiàn)分析(三)

    摘要:所以只針對(duì)同層級(jí)節(jié)點(diǎn)做比較,將復(fù)雜度的問題轉(zhuǎn)換成復(fù)雜度的問題。 React系列 React系列 --- 簡(jiǎn)單模擬語法(一)React系列 --- Jsx, 合成事件與Refs(二)React系列 --- virtualdom diff算法實(shí)現(xiàn)分析(三)React系列 --- 從Mixin到HOC再到HOOKS(四)React系列 --- createElement, ReactElem...

    sunsmell 評(píng)論0 收藏0
  • 深入React知識(shí)點(diǎn)整理(一)

    摘要:以我自己的理解,函數(shù)式編程就是以函數(shù)為中心,將大段過程拆成一個(gè)個(gè)函數(shù),組合嵌套使用。越來越多的跡象表明,函數(shù)式編程已經(jīng)不再是學(xué)術(shù)界的最愛,開始大踏步地在業(yè)界投入實(shí)用。也許繼面向?qū)ο缶幊讨螅瘮?shù)式編程會(huì)成為下一個(gè)編程的主流范式。 使用React也滿一年了,從剛剛會(huì)使用到逐漸探究其底層實(shí)現(xiàn),以便學(xué)習(xí)幾招奇技淫巧從而在自己的代碼中使用,寫出高效的代碼。下面整理一些知識(shí)點(diǎn),算是React看書...

    Gilbertat 評(píng)論0 收藏0
  • React && VUE Virtual DomDiff算法統(tǒng)一之路 snabbd

    摘要:毫無疑問的是算法的復(fù)雜度與效率是決定能夠帶來性能提升效果的關(guān)鍵因素。速度略有損失,但可讀性大大提高。因此目前的主流算法趨向一致,在主要思路上,與的方式基本相同。在里面實(shí)現(xiàn)了的算法與支持。是唯一添加的方法所以只發(fā)生在中。 VirtualDOM是react在組件化開發(fā)場(chǎng)景下,針對(duì)DOM重排重繪性能瓶頸作出的重要優(yōu)化方案,而他最具價(jià)值的核心功能是如何識(shí)別并保存新舊節(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)之間差異的方法,...

    shixinzhang 評(píng)論0 收藏0
  • VirtualDOMdiff(Vue實(shí)現(xiàn))

    摘要:如果以上情況均不符合,則通過會(huì)得到一個(gè),里面存放了一個(gè)為舊的,為對(duì)應(yīng)序列的哈希表。從這個(gè)哈希表中可以找到是否有與一致的舊的節(jié)點(diǎn),如果同時(shí)滿足,的同時(shí)會(huì)將這個(gè)真實(shí)移動(dòng)到對(duì)應(yīng)的真實(shí)的前面。 寫在前面 因?yàn)閷?duì)Vue.js很感興趣,而且平時(shí)工作的技術(shù)棧也是Vue.js,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。文章的原地址:https://github.com/ans...

    MAX_zuo 評(píng)論0 收藏0
  • vue源碼閱讀之?dāng)?shù)據(jù)渲染過程

    摘要:圖在中應(yīng)用三數(shù)據(jù)渲染過程數(shù)據(jù)綁定實(shí)現(xiàn)邏輯本節(jié)正式分析從到數(shù)據(jù)渲染到頁面的過程,在中定義了一個(gè)的構(gòu)造函數(shù)。一、概述 vue已是目前國內(nèi)前端web端三分天下之一,也是工作中主要技術(shù)棧之一。在日常使用中知其然也好奇著所以然,因此嘗試閱讀vue源碼并進(jìn)行總結(jié)。本文旨在梳理初始化頁面時(shí)data中的數(shù)據(jù)是如何渲染到頁面上的。本文將帶著這個(gè)疑問一點(diǎn)點(diǎn)追究vue的思路??傮w來說vue模版渲染大致流程如圖1所...

    AlphaGooo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<