vue diff演算法 patch
1、diff比較演算法
圖示:
diff比較只會在同層級進行, 不會跨層級比較。
程式碼示例
<!-- 之前 -->
<div> <!-- 層級1 -->
<p> <!-- 層級2 -->
<b> aoy </b> <!-- 層級3 -->
<span>diff</Span>
</P>
</div>
<!-- 之後 -->
<div> <!-- 層級1 -->
<p> <!-- 層級2 -->
<b> aoy </b> <!-- 層級3 -->
</p>
<span>diff</Span>
</div>
我們可能期望將<span>
直接移動到<p>
的後邊,這是最優的操作。
但是實際的diff操作是:
(1)<p>
移除裡的<span>
(2)建立一個新的<span>
<p>
的後邊。
因為新加的<span>
在層級2,舊的在層級3,屬於不同層級的比較。
vue原始碼中會有一個sameVnode方法:
function sameVnode (a, b) {
return (
a.key === b.key && (
(
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType (a, b)
) || (
isTrue(a.isAsyncPlaceholder) &&
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)
)
)
)
}
表示2個Vnode是否是同一個節點:
(1)當是一樣的節點,直接複用(若設定key的話)。
(2)當不是一樣的節點的話,新節點直接替換老節點。
2、比較原則
圖示:
圖師說明:
粉紅色的部分為oldNode,黃色的表示newNode。
s和e指標指向它們的頭child和尾child Node的指標。
現在分別對oldS、oldE、S、E兩兩做sameVnode比較,有四種比較方式。
即:
oldS == S?
oldS == E?
oldE == S?
oldE == E?
diff演算法:
如果是oldS和E匹配上了,那麼真實dom中的第一個節點會移到最後
如果是oldE和S匹配上了,那麼真實dom中的最後一個節點會移到最前,匹配上的兩個指標向中間移動
如果四種匹配沒有一對是成功的,那麼遍歷oldChild,S挨個和他們匹配,匹配成功就在真實dom中將成功的節點移到最前面,如果依舊沒有成功的,那麼將S對應的節點插入到dom中對應的oldS位置,oldS和S指標向中間移動。
3、key
不設key,newCh和oldCh只會進行頭尾兩端的相互比較。
設key後,除了頭尾兩端的比較外,還會從用key生成的物件oldKeyToIdx中查詢匹配的節點,所以為節點設定key可以更高效的利用dom。
(1)下圖是沒有設定key的diff演算法
(2)下圖是有設定key的diff演算法
參考文章:
https://www.cnblogs.com/wind-lanyan/p/9061684.html
https://segmentfault.com/a/1190000008782928?utm_source=tag-newest