揭秘Vue Diff算法

455 阅读4分钟

大家好,我是拾七,持续给大家补给前端干货🔥

Diff算法是什么?

diff算法是一种通过同层的树节点进行比较的高效算法。

    • 1、 比较只会在同层级进行,不会跨层级比较(同级比较)
    • 2、 在diff比较的过程中,循环从两边向中间比较 (双端比较)
    • 3、 在会发生变化的地方添加一个flag标记,下次发生变化的时候直接找该地方进行比较,被标记的节点在diff过程中不会比较(标记节点, Vue3优化)

Vue更新原理

当数据发生改变时,set方法会调用Dep.notify通知所有订阅者watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图。

源码解析

function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly{   if (oldVnode === vnode) return  // 处理差异}
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {  // 处理子节点}​

1、当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁2、通过isSameVnode进行判断,相同则调用patchNode方法
3、patchNode做了如下操作:

    • 找到对应的真实DOM,称为el

    • 如果都有文本节点且不想等,将el文本节点设置为Vnode的文本节点

    • 如果oldVnode有子节点而Vnode没有,则删除el自节点

    • 如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化后添加到el

    • 如果两者都有子节点,则执行updateChildren函数比较子节点

4、updateChildren主要做了以下操作(使用双指针):

    • 设置新旧Vnode的头尾指针
    • 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchNode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找key一致的Vnode节点再分情况操作。

子节点列表使用双指针对比

  • 使用双指针对比是一种常见的优化策略,用于在进行 Virtual DOM diff 比较时,尽可能地减少比较的时间复杂度。

  • 在这种优化策略中,对比新旧子节点列表时,使用两个指针分别指向新旧列表的起始位置和结束位置,然后从两端同时向中间遍历,逐个比较节点,以确定需要进行哪些更新操作。

  • 具体来说,可以采取以下步骤进行对比:

  •   1. 初始化两个指针,分别指向新旧列表的起始位置和结束位置。  
      2. 使用循环或递归方式,从两端向中间遍历新旧子节点列表。  
      3. 在遍历过程中,逐个比较新旧子节点,判断是否需要进行更新操作。  
      4. 如果发现有节点需要更新,根据具体情况执行插入、删除、移动或更新等操作。  
      5. 当两个指针相遇时,说明已经完成了整个列表的对比。
     
    

使用双指针对比子节点列表可以有效地减少比较的时间复杂度,尤其是在列表长度较大的情况下。通过同时从两端向中间遍历,可以尽可能地提前发现差异,从而减少不必要的遍历和比较操作。


Vue 的 Virtual DOM diff 算法与 React 中的算法有些类似:

1. 初始化渲染:

  • 首次渲染时,Vue 会将模板编译成虚拟 DOM 树,并将其与实际 DOM 进行比较,然后将差异更新到实际 DOM 上。

2. 生成虚拟 DOM 树:

  • Vue 组件中的模板会被编译成一个渲染函数,渲染函数会返回一个虚拟 DOM 树。
  • 虚拟 DOM 是一个轻量级的 JavaScript 对象树,它与实际的 DOM 结构一一对应,但不包含真实的 DOM 属性和方法。

3. 比较两个虚拟 DOM 树:

  •     当组件状态发生变化时,Vue 会重新渲染组件并生成新的虚拟 DOM 树。

  •     Vue 的 diff 算法会比较新旧两个虚拟 DOM 树的差异,以确定需要更新的部分。

4. 更新实际 DOM:

  • Vue 的 diff 算法会尽量复用已有的 DOM 节点,只对需要更新的部分进行更新,而不是对整个 DOM 树进行重新渲染。

  • 在更新实际 DOM 时,Vue 会尽可能地使用高效的 DOM 操作方法,以减少页面重绘和重排的次数,提高页面性能和响应性。

Vue 的 diff 算法具体实现了一些优化策略,例如同级比较、双端比较、标记节点等,以尽可能减少比较的时间复杂度,并提高算法的效率和性能。Vue 还允许开发者通过一些手动优化技巧(如使用 key 属性)来进一步优化 diff 算法的性能。总的来说,Vue 的 diff 算法在保证页面更新效率的同时,也尽可能地减少了开发者的工作量。