思路分析

1、diff算法是干什么的?
2、它的必要性
3、它何时执行
4、具体执行方式
5、拔高:说一下vue3中的优化

回答范例

1、Vue中的diff算法称为Patching算法,它是由Snabbdom修改而来,虚拟dom转化为真实dom需要通过patch方法转换。
2、最初Vue1.x视图中每个依赖均有更新函数对应,可以做到精准更新,因此不需要patching算法和虚拟dom支持。这样导致了Vue1.x无法承载大型应用
Vue2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之相对应,从而需要引入patching算法才能精确到发生变化的地方并高效更新。

3、vue中diff执行的时刻:是组件内响应式数据变更触发组件实例执行其更新函数,更新函数会再次执行render函数获取最新的虚拟dom,然后通过patch函数,传入两次虚拟dom,进行diff算法,找到变更的节点,进行更新生成真实的dom操作。

4、patch过程是一个递归过程,遵循深度优先,同层比较的策略【树形结构的递归遍历的时间负责度是O(n)的三次方,浪费】,以vue3的patch为例:

  • 首先判断两个根节点是否为相同同类节点,不同则删除重新创建 【判断key, type】
  • 如果双方都是文本节点则更新文本内容
  • 如果双方都是元素节点,则递归更新子元素,同时更新元素属性
  • 更新子节点的几种情况:
    • 新的节点为文本,老得节点是数组,则清空数组设置为文本;
    • 新的节点为文本,老得节点是文本,则直接设置文本
    • 新的节点为数组,老得节点是文本,则清空文本, 创建新的子节点中的子元素
    • 新的节点为数组,老得节点是数组,比较两个子节点,继续updateChild updaetChildren进行优化算法

【优化算法:vue2中是双端优化算法,先从开头结尾寻找相同节点,如果找到相同节点,直接做比对优化。在实际项目中首尾相同概率非常大,不要直接遍历,浪费性能。 如果要遍历,找到其中一个数组,通过key进行缓存,在另外数组中寻找节点,则非常节省时间】
【优化算法:vue3中做了编译优化,编译的时候,可以找到动态的部分,例如,编译时发现只有文本有动态变化,则针对文本节点进行标记 patchflag。
编译优化:主要做二进制标记,可以标记哪些是动态的(属性、文本、字节点等等),有效节省了更新效率。

源码如下:componentUpdateFn

  • 如果已经挂载,则直接进行patch更新,patch算法传入两个参数prevTree、nextTree-两次虚拟dom树
  • nextTree 是由当前组件实例的渲染函数执行之后得到
  • prevTree 是组件实例的subtree
  • patch逻辑如4所示, 如果是元素节点,则会执行patchElement,从新的节点中获取到patchflag【编译器优化的标志符】
  • patchflag可以精确表示组件的结构、形态、如何去更新,根据patchflag不同的值(属性、class、text等都有不同的值区分),执行不同的更新逻辑。如果有子元素,则进行双端优化等等。

5、vue3中引入的更新策略:编译器优化patchflags、block等。


总结:大功告成✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️