你了解vue中的diff算法吗?
题目分析:vue基于虚拟DOM做更新,diff又是其核心部分,因此常被问道,此题考查面试者深度。
分析
必问题目,涉及vue更新原理,比较考查理解深度。
思路
- diff算法是干什么的
- 它的必要性
- 它何时执行
- 具体执行方式
- 拔高:说一下vue3中的优化
回答范例
1.Vue中的diff算法称为patching算法,它由Snabbdom修改而来,虚拟DOM要想转化为真实DOM就需要通过patch方法转换。
2.最初Vue1.x视图中每个依赖均有更新函数对应,可以做到精准更新,因此并不需要虚拟DOM和patching算法支持,但是这样粒度过细导致Vue1.x无法承载较大应用;Vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,此时就需要引入patching算法才能精确找到发生变化的地方并高效更新。
3.vue中diff执行的时刻是组件内响应式数据变更触发实例执行其更新函数时,更新函数会再次执行render函数获得最新的虚拟DOM,然后执行patch函数,并传入新旧两次虚拟DOM,通过比对两者找到变化的地方,最后将其转化为对应的DOM操作。
4.patch过程是一个递归过程,遵循深度优先、同层比较的策略;以vue3的patch为例:
-
首先判断两个节点是否为相同同类节点,不同则删除重新创建
-
如果双方都是文本则更新文本内容
-
如果双方都是元素节点则递归更新子元素,同时更新元素属性
-
更新子节点时又分了几种情况:
- 新的子节点是文本,老的子节点是数组则清空,并设置文本;
- 新的子节点是文本,老的子节点是文本则直接更新文本;
- 新的子节点是数组,老的子节点是文本则清空文本,并创建新子节点数组中的子元素;
- 新的子节点是数组,老的子节点也是数组,那么比较两组子节点,更新细节blabla
- vue3中引入的更新策略:编译期优化patchFlags、block等
知其所以然
patch关键代码
说一下Diff算法?
要点: patch、patchVnode、updateChildren、vue优化时间复杂度为O(n)
答:
Diff算法比较过程:
第一步: patch函数中对新老节点进行比较。如果新节点不存在就销毁老节点;如果老节点不存在,直接创建新的节点;当两个节点是相同节点的时候,进入 patctVnode 的过程,比较两个节点的内部。
第二步: patchVnode函数比较两个虚拟节点内部。如果两个虚拟节点完全相同,返回;当前vnode 的children 不是textNode,再分成三种情况:
- 有新children,没有旧children,创建新的;
- 没有新children,有旧children,删除旧的 ;
- 新children、旧children都有,执行
updateChildren比较children的差异,这里就是diff算法的核心。当前vnode 的children 是textNode,直接更新text。
第三步: updateChildren函数子节点进行比较。
- 第一步 头头比较。若相似,旧头新头指针后移(即
oldStartIdx++&&newStartIdx++),真实dom不变,进入下一次循环;不相似,进入第二步。 - 第二步 尾尾比较。若相似,旧尾新尾指针前移(即
oldEndIdx--&&newEndIdx--),真实dom不变,进入下一次循环;不相似,进入第三步。 - 第三步 头尾比较。若相似,旧头指针后移,新尾指针前移(即
oldStartIdx++&&newEndIdx--),未确认dom序列中的头移到尾,进入下一次循环;不相似,进入第四步。 - 第四步 尾头比较。若相似,旧尾指针前移,新头指针后移(即
oldEndIdx--&&newStartIdx++),未确认dom序列中的尾移到头,进入下一次循环;不相似,进入第五步。 - 第五步 若节点有key且在旧子节点数组中找到sameVnode(tag和key都一致),则将其dom移动到当前真实dom序列的头部,新头指针后移(即
newStartIdx++);否则,vnode对应的dom(vnode[newStartIdx].elm)插入当前真实dom序列的头部,新头指针后移(即newStartIdx++)。 - 但结束循环后,有两种情况需要考虑:
- 新的字节点数组(newCh)被遍历完(
newStartIdx > newEndIdx)。那就需要把多余的旧dom(oldStartIdx -> oldEndIdx)都删除,上述例子中就是c,d; - 新的字节点数组(oldCh)被遍历完(
oldStartIdx > oldEndIdx)。那就需要把多余的新dom(newStartIdx -> newEndIdx)都添加。
- 新的字节点数组(newCh)被遍历完(
1.出现:主流框架中多采用VNode更新结点,更新规则为diff算法。
2.原理:框架会将所有的结点先转化为虚拟节点Vnode,在发生更改后将VNode和原本页面的OldNode进行对比,然后以VNode为基准,在oldNode上进行准确的修改。(修改准则:原本没有新版有,则增加;原本有新版没有,则删除;都有则进行比较,都为文本结点则替换值;都为静态资源不处理;都为正常结点则替换)