Vue diff

287 阅读2分钟

同层比较深度优先

思路

  • diff算法是什么?
  • 它的必要性
  • 何时执行
  • 具体执行方式
  • 拔高:说一下vue3中的优化

总结

  • Vue中的diff算法又称为patching算法,它由Snabbdom修改而来,虚拟DOM要想转换为真实dom需要通过patch方法转换

  • Vue1.x视图中每个依赖均有更新函数对应(WatcherDep),可以做到精准更新,因此并不需要虚拟dom和patching算法支持。但是这样粒度过细导致Vue1.x无法承载较大应用;同时保存太多的依赖关系,消耗内存

  • Vue2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,此时就需要引入patching算法才能准确找到发生变化的地方并高效更新

  • vue中的diff执行的时刻是组件内响应式数据变更触发实例执行其更新函数时,更新函数会执行render函数获得最新的虚拟DOM,然后执行patch函数,并传入新旧两次虚拟DOM,通过比对两者找到变化的地方,最后将其转化为对应的DOM操作

响应式数据变更 ----> 执行更新函数 ----> 执行render函数 ---> 最新的vdom ----> 执行patch函数 ----> 对比找到变化的地方 ----> 转换为对应的DOM操作

diff的过程

遍历树的时间复杂度是O(n).但是比较两棵树的时间复杂度是O(n^3)

所以diff过程是一个递归过程,遵循深度优先、同层比较的策略。把时间复杂度控制在O(n^2)

所以同层比较后,就可以缩短比较两棵树的时间复杂度。因为考虑到不会乱跳层,如果存在跳层,直接删除、新建

深度优先执行顺序: 381648221312_.pic.jpg

  • 首先判断两个节点是否是相同同类节点,不同则删除重新创建
  • 如果双方都是文本则更新文本内容
  • 如果双方都是元素节点则递归更新子元素(这个就是所谓的深度优先),同时更新元素属性
  • 更新子节点时又分了几种情况:
    • 新的子节点是文本,老的子节点是数组则清空,并设置文本
    • 新的子节点是文本,老的子节点是文本则直接更新文本
    • 新的子节点是数组,老的子节点是文本则清空文本,并创建新子节点数组中的子元素
    • 新的子节点是数组,老的子节点也是数组,那么比较两组子节点,更新细节balabala。都是数组是关键的diff算法