# 浅学习一下 diff 算法

# 什么是 diff 算法?

Diff 算法是一种对比算法。对比两者是旧虚拟 DOM 和新虚拟 DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实 DOM,进而提高效率。

# diff 算法做了什么?

  1. 当数据改变时,会触发 setter,并且通过 Dep.notify 去通知所有订阅者 Watcher,订阅者们就会调用 patch 方法,给真实 DOM 打补丁,更新相应的视图。
  2. patch 方法的作用就是,对比当前同层的虚拟节点是否为同一种类型的标签,是:继续执行 patchVnode 方法进行深层比对;否:没必要比对了,直接整个节点替换成新虚拟节点
  3. patch 中用 sameVnode 方法和 patchVnode 方法判断是否为同一类型节点(key 值一样,标签一样,是否都为注释,是否都定义了 data),如果不是同一节点,则直接替换
  • key 值是否一样?标签名是否一样?是否都为注释节点?是否都定义了 data?当标签为 input 时,type 必须是否相同?
  1. patchVnode 方法
  • 找到对应的真实 DOM,称为 el
  • 判断 newVnode 和 oldVnode 是否指向同一个对象,如果是,那么直接 return
  • 如果他们都有文本节点并且不相等,那么将 el 的文本节点设置为 newVnode 的文本节点。
  • 如果 oldVnode 有子节点而 newVnode 没有,则删除 el 的子节点
  • 如果 oldVnode 没有子节点而 newVnode 有,则将 newVnode 的子节点真实化之后添加到 el
  • 如果两者都有子节点,则执行 updateChildren 函数比较子节点

# 使用 diff 的好处?

  • 性能大大提升,减少频繁操作节点带来的性能损耗

    • 使用虚拟 DOM 算法的损耗计算: 总损耗 = 虚拟 DOM 增删改+(与 Diff 算法效率有关)真实 DOM 差异增删改+(较少的节点)排版与重绘

    • 直接操作真实 DOM 的损耗计算: 总损耗 = 真实 DOM 完全增删改+(可能较多的节点)排版与重绘

  • 新旧虚拟 DOM 对比的时候,Diff 算法比较只会在同层级进行, 不会跨层级比较。 所以 Diff 算法是:深度优先算法。 时间复杂度:O(n)

# 为什么不能用index作为循环的 key 值呢?

  • Diff 算法借助元素的 Key 判断元素是新增、删除、修改,从而减少不必要的元素重渲染。
  • 当列表第一项插入一个元素时,key 值为 0,之后的元素的 key 会依次变更,从而全部更新,而原先最后一个元素由于 key 值为原来的index+1,会被认为是新增的,导致前面元素数据的绑定不正确
Last Updated: 8/27/2023, 11:07:46 AM