-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
面试官:了解过vue中的diff算法吗?说说看 #24
Comments
《Vue3 Diff 之 patchKeyedChildren》 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
一、是什么
diff
算法是一种通过同层的树节点进行比较的高效算法其有两个特点:
diff
算法的在很多场景下都有应用,在vue
中,作用于虚拟dom
渲染成真实dom
的新旧VNode
节点比较二、比较方式
diff
整体策略为:深度优先,同层比较下面举个
vue
通过diff
算法更新的例子:新旧
VNode
节点如下图所示:第一次循环后,发现旧节点D与新节点D相同,直接复用旧节点D作为
diff
后的第一个真实节点,同时旧节点endIndex
移动到C,新节点的startIndex
移动到了 C第二次循环后,同样是旧节点的末尾和新节点的开头(都是 C)相同,同理,
diff
后创建了 C 的真实节点插入到第一次创建的 B 节点后面。同时旧节点的endIndex
移动到了 B,新节点的startIndex
移动到了 E第三次循环中,发现E没有找到,这时候只能直接创建新的真实节点 E,插入到第二次创建的 C 节点之后。同时新节点的
startIndex
移动到了 A。旧节点的startIndex
和endIndex
都保持不动第四次循环中,发现了新旧节点的开头(都是 A)相同,于是
diff
后创建了 A 的真实节点,插入到前一次创建的 E 节点后面。同时旧节点的startIndex
移动到了 B,新节点的startIndex
移动到了 B第五次循环中,情形同第四次循环一样,因此
diff
后创建了 B 真实节点 插入到前一次创建的 A 节点后面。同时旧节点的startIndex
移动到了 C,新节点的 startIndex 移动到了 F新节点的
startIndex
已经大于endIndex
了,需要创建newStartIdx
和newEndIdx
之间的所有节点,也就是节点F,直接创建 F 节点对应的真实节点放到 B 节点后面三、原理分析
当数据发生改变时,
set
方法会调用Dep.notify
通知所有订阅者Watcher
,订阅者就会调用patch
给真实的DOM
打补丁,更新相应的视图源码位置:src/core/vdom/patch.js
patch
函数前两个参数位为oldVnode
和Vnode
,分别代表新的节点和之前的旧节点,主要做了四个判断:destory
钩子createElm
sameVnode
判断节点是否一样,一样时,直接调用patchVnode
去处理这两个节点下面主要讲的是
patchVnode
部分patchVnode
主要做了几个判断:dom
的文本内容为新节点的文本内容DOM
,并且添加进父节点DOM
删除子节点不完全一致,则调用
updateChildren
while
循环主要处理了以下五种情景:VNode
节点的start
相同时,直接patchVnode
,同时新老VNode
节点的开始索引都加 1VNode
节点的end
相同时,同样直接patchVnode
,同时新老VNode
节点的结束索引都减 1VNode
节点的start
和新VNode
节点的end
相同时,这时候在patchVnode
后,还需要将当前真实dom
节点移动到oldEndVnode
的后面,同时老VNode
节点开始索引加 1,新VNode
节点的结束索引减 1VNode
节点的end
和新VNode
节点的start
相同时,这时候在patchVnode
后,还需要将当前真实dom
节点移动到oldStartVnode
的前面,同时老VNode
节点结束索引减 1,新VNode
节点的开始索引加 1VNode
为key
值,对应index
序列为value
值的哈希表中找到与newStartVnode
一致key
的旧的VNode
节点,再进行patchVnode
,同时将这个真实dom
移动到oldStartVnode
对应的真实dom
的前面createElm
创建一个新的dom
节点放到当前newStartIdx
的位置小结
watcher
就会调用patch
给真实的DOM
打补丁isSameVnode
进行判断,相同则调用patchVnode
方法patchVnode
做了以下操作:dom
,称为el
el
文本节点设置为Vnode
的文本节点oldVnode
有子节点而VNode
没有,则删除el
子节点oldVnode
没有子节点而VNode
有,则将VNode
的子节点真实化后添加到el
updateChildren
函数比较子节点updateChildren
主要做了以下操作:VNode
的头尾指针patchVnode
进行patch
重复流程、调用createElem
创建一个新节点,从哈希表寻找key
一致的VNode
节点再分情况操作参考文献
The text was updated successfully, but these errors were encountered: