最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue源碼解讀子節(jié)點優(yōu)化更新

 更新時間:2022年08月20日 17:09:20   作者:JiaJi  
這篇文章主要為大家介紹了vue源碼解讀子節(jié)點優(yōu)化更新示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

Vue中更新節(jié)點,當新 VNode 和舊 VNode 都是元素節(jié)點且都有子節(jié)點時,Vue會循環(huán)對比新舊 VNode 的子節(jié)點數(shù)組,然后根據(jù)不同情況做不同處理。

雖然這種方法能解決問題,但是當更新子節(jié)點特別多時,循環(huán)算法的時間復雜度就會很高,所以Vue對此進行了優(yōu)化。

優(yōu)化前存在的問題

現(xiàn)在有新的 newChildren 數(shù)組和舊的 oldChildren 數(shù)組:

newChildren = ['a','b','c','d'];
oldChildren = ['a','b','c','e'];

按照之前的解決方案:先循環(huán) newChildren 數(shù)組,把第一個節(jié)點與 oldChildren 里的子節(jié)點逐一對比,再根據(jù)情況去處理。如果像上面的代碼一樣,前三個子節(jié)點都沒有變化,只修改了最后一個子節(jié)點,但因為循環(huán)查找,還是要循環(huán)16次才能發(fā)現(xiàn),所以前面做的15次循環(huán)全是無用功。

優(yōu)化策略分析

Vue的策略是不按照循序去循環(huán) newChildrenoldChildren 這兩個數(shù)組,而是先去比較特殊位置的子節(jié)點,比如:

  • newChildren 數(shù)組里的第一個未處理子節(jié)點和 oldChildren 數(shù)組的第一個未處理子節(jié)點做對比,如果相同,就更新節(jié)點。
  • 如果不同,把 newChildren數(shù)組里最后一個未處理子節(jié)點和 oldChildren 數(shù)組里最后一個未處理子節(jié)點做比對,如果相同,就更新節(jié)點。
  • 如果不同,把 newChildren數(shù)組里最后一個未處理子節(jié)點和 oldChildren 數(shù)組里第一個未處理子節(jié)點做比對,如果相同,就更新節(jié)點。
  • 如果不同,把 newChildren數(shù)組里第一個未處理子節(jié)點和 oldChildren 數(shù)組里最后一個未處理子節(jié)點做比對,如果相同,就更新節(jié)點。
  • 如果四種情況試完如果還不同,就按照之前循環(huán)的方式來查找節(jié)點。

四種情況分別分別被稱作:

不相同才往后繼續(xù)。

  • 新前與舊前
  • 如果相同,直接更新,因為位置也相同,無需移動。
  • 新后與舊后
  • 如果相同,直接更新,因為位置也相同,無需移動。
  • 新后與舊前
  • 如果相同,更新,但因為位置不同,所以需要移動位置
  • 新前與舊后
  • 如果相同,更新,但因為位置不同,所以需要移動位置

如果上面的情況都不滿足,再通過之前的循環(huán)方式查找

源碼解析

從上面的優(yōu)化策略中,知道對比子節(jié)點是先對比特殊位置的子節(jié)點,對比成功就進行更新處理,也就是說有可能處理第一個,也有可能是處理最后一個,所以在循環(huán)的時候就不可能只是從前往后循環(huán),而是從兩邊向中間循環(huán)。

首先定義四個變量

  • newStartIdx:新子節(jié)點數(shù)組里開始位置的下標;
  • newEndIdx:新子節(jié)點數(shù)組里結(jié)束位置的下標;
  • oldStartIdx:舊子節(jié)點數(shù)組里開始位置的下標;
  • oldEndIdx:舊子節(jié)點數(shù)組里結(jié)束位置的下標;

在循環(huán)的時候,每處理一個節(jié)點,就將下標向圖中箭頭的方向移動一個位置,newStartIdxoldStartIdx 往后加1,newEndIdxoldEndIdx往前減1。

理解了這個概念后,就可以解析源碼了:

定義需要的變量

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
    let oldStartIdx = 0               // oldChildren開始索引
    let oldEndIdx = oldCh.length - 1   // oldChildren結(jié)束索引
    let oldStartVnode = oldCh[0]        // oldChildren中所有未處理節(jié)點中的第一個
    let oldEndVnode = oldCh[oldEndIdx]   // oldChildren中所有未處理節(jié)點中的最后一個
?
    let newStartIdx = 0               // newChildren開始索引
    let newEndIdx = newCh.length - 1   // newChildren結(jié)束索引
    let newStartVnode = newCh[0]        // newChildren中所有未處理節(jié)點中的第一個
    let newEndVnode = newCh[newEndIdx]  // newChildren中所有未處理節(jié)點中的最后一個A
}

如果 oldStartVNode 不存在,則跳過,將 oldStartIdx 加1,對比下一個

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    if (isUndef(oldStartVnode)) {
        oldStartVnode = oldCh[++oldStartIdx];
    }
}

如果oldEndVnode不存在,則跳過,將oldEndIdx減1,比對前一個

else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx];
}

如果新前與舊前節(jié)點相同,就把兩個節(jié)點進行patch更新,同時oldStartIdxnewStartIdx都加1,后移一個位置

else if (sameVnode(oldStartVnode, newStartVnode)) {
    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue)
    oldStartVnode = oldCh[++oldStartIdx]
    newStartVnode = newCh[++newStartIdx]
}

如果新后與舊后節(jié)點相同,就把兩個節(jié)點進行patch更新,同時oldEndIdxnewEndIdx都減1,前移一個位置

else if (sameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue)
    oldEndVnode = oldCh[--oldEndIdx]
    newEndVnode = newCh[--newEndIdx]
}

如果新后與舊前節(jié)點相同,先把兩個節(jié)點進行patch更新,然后把舊前節(jié)點移動到oldChilren中所有未處理節(jié)點之后,最后把oldStartIdx加1,后移一個位置,newEndIdx減1,前移一個位置

else if (sameVnode(oldStartVnode, newEndVnode)) {
    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
    oldStartVnode = oldCh[++oldStartIdx]
    newEndVnode = newCh[--newEndIdx]
}

如果新前與舊后節(jié)點相同,先把兩個節(jié)點進行patch更新,然后把舊后節(jié)點移動到oldChilren中所有未處理節(jié)點之前,最后把newStartIdx加1,后移一個位置,oldEndIdx減1,前移一個位置

else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
    oldEndVnode = oldCh[--oldEndIdx]
    newStartVnode = newCh[++newStartIdx]
}
  • 不屬于以上四種情況,就進行常規(guī)的循環(huán)比對patch。

如果oldStartIdx大于oldEndIdx了,那就表示oldChildrennewChildren先循環(huán)完畢,那么newChildren里面剩余的節(jié)點都是需要新增的節(jié)點,把[newStartIdx, newEndIdx]之間的所有節(jié)點都插入到OldChildren中。

if (oldStartIdx > oldEndIdx) {
    refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
    addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
}

如果newStartIdx大于newEndIdx了,那就表示newChildrenoldChildren先循環(huán)完畢,那么oldChildren里面剩余的節(jié)點都是需要刪除的節(jié)點,把[oldStartIdx, oldEndIdx]之間的所有節(jié)點都刪除

else if (newStartIdx > newEndIdx) {
    removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
}

小結(jié)

  • 分析了循環(huán)更新子節(jié)點存在的性能問題,數(shù)據(jù)量大時,時間復雜度高。
  • 分析Vue中的優(yōu)化策略,先對比特殊位置的子節(jié)點,分別是:新前與舊前、新后與舊后、新后與舊前、新前與舊后。如果都不相同,在通過循環(huán)遍歷對比。
  • 理解源碼,通過源碼解析,在腦海中繪制一條清晰的思路線。

參考自Vue源碼系列-Vue中文社區(qū)

以上就是vue源碼解讀子節(jié)點優(yōu)化更新的詳細內(nèi)容,更多關(guān)于Vue子節(jié)點更新的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 從零開始搭建vue移動端項目到上線的步驟

    從零開始搭建vue移動端項目到上線的步驟

    這篇文章主要介紹了從零開始搭建vue移動端項目到上線的步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • vue-router?導航完成后獲取數(shù)據(jù)的實現(xiàn)方法

    vue-router?導航完成后獲取數(shù)據(jù)的實現(xiàn)方法

    這篇文章主要介紹了vue-router?導航完成后獲取數(shù)據(jù),通過使用生命周期的 created() 函數(shù),在組件創(chuàng)建完成后調(diào)用該方法,本文結(jié)合實例代碼給大家講解的非常詳細需要的朋友可以參考下
    2022-11-11
  • Vue2.0基于vue-cli+webpack同級組件之間的通信教程(推薦)

    Vue2.0基于vue-cli+webpack同級組件之間的通信教程(推薦)

    下面小編就為大家?guī)硪黄猇ue2.0基于vue-cli+webpack同級組件之間的通信教程(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Vue input輸入框中的值如何變成黑點問題

    Vue input輸入框中的值如何變成黑點問題

    這篇文章主要介紹了Vue input輸入框中的值如何變成黑點問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Vite創(chuàng)建項目的實現(xiàn)步驟

    Vite創(chuàng)建項目的實現(xiàn)步驟

    隨著 Vite2 的發(fā)布并日趨穩(wěn)定,現(xiàn)在越來越多的項目開始嘗試使用它。本文我們就介紹了Vite創(chuàng)建項目的實現(xiàn)步驟,感興趣的可以了解一下
    2021-07-07
  • vue使用mixins優(yōu)化組件

    vue使用mixins優(yōu)化組件

    這篇文章主要介紹了vue如何使用mixins優(yōu)化組件,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下
    2021-04-04
  • Vue.js實戰(zhàn)之使用Vuex + axios發(fā)送請求詳解

    Vue.js實戰(zhàn)之使用Vuex + axios發(fā)送請求詳解

    這篇文章主要給大家介紹了關(guān)于Vue.js使用Vuex與axios發(fā)送請求的相關(guān)資料,文中介紹的非常詳細,相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • 詳解 vue.js用法和特性

    詳解 vue.js用法和特性

    Vue.js目前已經(jīng)更新到2.x,功能和語法上有一定升級和修改,本文首先介紹基礎(chǔ)內(nèi)容。感興趣的朋友一起看看吧
    2017-10-10
  • Vue.js仿微信聊天窗口展示組件功能

    Vue.js仿微信聊天窗口展示組件功能

    這篇文章主要介紹了Vue.js仿微信聊天窗口展示組件功能,需要的朋友可以參考下
    2017-08-08
  • vue實現(xiàn)el-select默認選擇第一個或者第二個

    vue實現(xiàn)el-select默認選擇第一個或者第二個

    這篇文章主要介紹了vue實現(xiàn)el-select默認選擇第一個或者第二個,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評論

乐昌市| 西吉县| 康乐县| 卢龙县| 松潘县| 黑水县| 沧源| 桐柏县| 志丹县| 乌审旗| 灵台县| 富裕县| 丹凤县| 景洪市| 新晃| 古交市| 兰州市| 砀山县| 文安县| 晋宁县| 东方市| 封丘县| 上虞市| 游戏| 独山县| 璧山县| 什邡市| 鄂尔多斯市| 鄢陵县| 桑植县| 绿春县| 乌兰浩特市| 嘉定区| 新竹市| 东至县| 周至县| 寿光市| 镇赉县| 新乡市| 中牟县| 互助|