最近碰到部分業務場景,代碼邏輯須要瞭解"數組變動後,具體變動了哪一些元素,以及變動的位置..."。因而仔細研究並覆寫了一遍針對數組變化的diff算法,在這裏作下diff算法的邏輯分享&&源碼解讀vue
咱們先了解diff方法的運行規則和前提方法.node
1.虛擬node進行深度優先 && 同級對比算法
深度優先: 同級對比 如上面圖所示:數組
每次vnode都是執行同級對比(對應dom同一個父元素)微信
代碼邏輯以下圖: 2.簡單判斷markdown
sameVnode函數用來進行判斷是不是同一個vnode元素。dom
源代碼: 如圖所示: 這裏有兩個重要元素:函數
key : 開發者定義的」:key」優化
sel: 元素tagName+元素id+元素classspa
sel的定義源碼以下: vNode構建函數: 3.構建索引 邏輯如圖:
儘可能不新增/刪除dom,如圖下所示: 若是是相同vnode,源碼以下:
1.首先會進行時間複雜度 O(n)的while循環,循環條件爲 "遍歷舊節點數組&&遍歷新節點數組,誰先遍歷完循環就結束" ,源碼以下圖: 在每次的循環過程當中,會有兩大類判斷方法:
1-1.首尾比較 && 首尾序號 邏輯:如圖上所示,首先在循環遍歷前 標記好新,舊節點數組的開始位置和結束位置的序號:oldStartIdx、oldEndIdx、newStartIdx、newEndIdx;其次在循環遍歷的過程當中採用 "首首比較,尾尾比較,首尾比較";
源碼以下: 若是數據爲圖上所示,那麼根據首尾比較方法會有以下圖所示結果,最終所有執行了更新操做: 1-2.索引比較 -- 最壞狀況,這裏的時間複雜度也是O(n),即整個算法複雜度O(n)+O(n)
每次遍歷的過程當中可能存在"新數組節點新增/舊數組節點刪除",那麼先後對比就知足不了條件。這裏邏輯會進入索引比較;
好比這種狀況: 那麼,循環中會執行一遍 建立舊數組的索引對象。
那麼從建立到比較的整個邏輯圖以下: 這裏的源碼以下: 1-2.1 當舊節點不存在新增的節點時,進行當前oldStartIdx位置的添加: 源碼以下: 1-2.2 當舊數組存在節點,那麼進行位置移動: 源碼: 1.3 當節點遍歷完以後:
會存在兩種狀況,「新數組已經遍歷完,但舊數組沒有遍歷完成」 || 「舊數組遍歷完成,但新數組沒有遍歷完成」.
故源代碼的判斷以下: 1.3.1 舊數組沒有循環完成:
舊數組沒有循環完成的效果以下圖所示: 這裏注意一個點,咱們每次的節點更新會移動序號,即便被刪除的節點不在一塊 最終也會被 首尾比較算法 "摞在一塊" 即 (oldStartIdx~oldEndIdx)。上圖所示更加明顯一些。
源碼在這裏就進行批量刪除: 1.3.2 新數組沒有循環完成:
效果以下圖所示: 通過 先後對比&&索引 的過濾後,只會存在 新.末尾節點!==舊節點 及以前的連續的新節點(!==舊節點);
因此這裏也被 "摞在一塊" ,即 (newStartIdx~newEndIdx)
源碼以下: 這樣,整個diff的對比算法就已經走完了。因此核心就是:先後對比+索引
關鍵點大概以下
vue3.0針對"無腦"patchVnode進行了過濾 -- 靜態類型Vnode:
老版的源碼: 這裏,咱們再重複下vue2.x系列的對比更新邏輯: 新版的vue3.0增長了 靜態類型Vnode,若是是靜態類型的vnode 那麼直接跳過更新,修改新節點引用便可: 備註:comment類型 目前翻到它的源碼也只是更改引用,源碼做者加上了一行註釋: 這裏再多插一句,fragment 碎片類型 爲新增的vnode類型, 即: vue3.0的過濾判斷源碼以下:
更多精彩內容,盡請關注騰訊VTeam技術團隊微信公衆號和視頻號
原做者:陳碧鬆
未經贊成,禁止轉載!