Diff算法是什么?

Diff算法用于对比新旧虚拟DOM树,通过精确识别变化的节点,只更新必要的部分,提高DOM操作效率。它避免跨级比较,将时间复杂度降低。当数据改变时,watcher调用patch方法,通过isSameVnode和patchVnode更新DOM。对于有子节点的情况,updateChildren函数负责匹配和更新子节点,确保高效更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

他的对比过程如下:

在新老虚拟 DOM 对比时:

  • 首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换
  • 如果为相同节点,进行 patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的 children 没有子节点,将旧的子节点移除)
  • 比较如果都有子节点,则进行 updateChildren,判断如何对这些新老节点的子节点进行操作(diff 核心)。
  • 匹配时,找到相同的子节点,递归比较子节点

在 diff 中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从 O(n3)降低值 O(n),也就是说,只有当新旧 children 都为多个子节点时才需要用核心的 Diff 算法进行同层级比较。

虚拟 DOM 算法和真实 DOM 算法比较:

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

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

小结:

  • 当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
  • 通过isSameVnode进行判断,相同则调用patchVnode方法
  • patchVnode做了以下操作:
    • 找到对应的真实dom,称为el
    • 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
    • 如果oldVnode有子节点而VNode没有,则删除el子节点
    • 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
    • 如果两者都有子节点,则执行updateChildren函数比较子节点
  • updateChildren主要做了以下操作:
    • 设置新旧VNode的头尾指针
    • 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作

 

### Diff算法的定义与原理 Diff算法是一种用于比较两个数据结构之间差异的技术,广泛应用于前端开发中虚拟DOM的更新过程。它的主要目的是通过计算新旧状态之间的最小差异集合,从而减少不必要的操作,提升性能[^2]。 在具体的实现层面,Diff算法的核心思想是对两棵虚拟DOM树进行逐层对比。由于HTML文档本质上是一个嵌套层次分明的树形结构,因此该算法采用了深度优先遍历的方式逐一匹配节点,并记录它们的变化情况[^4]。 --- ### Diff算法的具体流程 以下是Diff算法的一般工作流程: 1. **同层级比较**:只在同一级别内的兄弟节点间寻找相同类型的子节点进行一对一配对;如果找不到完全一致的对象,则尝试移动现有元素或者新增缺失部分。 2. **跨层级重组检测**:虽然理想情况下希望保持简单的线性扫描模式,但实际上某些复杂场景可能涉及更深层次的关系调整——即所谓的“key”属性便是在这里发挥作用的关键所在。借助唯一的`key`标识符可以帮助快速定位特定项的位置关系,进而简化判断逻辑并加快查找效率[^4]。 3. **递归深入子树**:一旦确认当前层面上存在改动之处之后,便会继续向下一层展开进一步分析直至抵达叶子节点为止。 ```javascript function diff(oldTree, newTree) { if (!oldTree || !newTree) return; // Step 1: Compare node types. if (oldTree.type !== newTree.type) { replaceNode(oldTree, newTree); return; } // Step 2: Update attributes and properties of the same type nodes. updateAttributes(oldTree, newTree); // Step 3: Recursively compare children. reconcileChildren(oldTree.children, newTree.children); } ``` --- ### 在性能优化中的作用 #### 1. **最小化真实DOM操作** 传统方式每次都需要彻底替换掉整个区域的内容才能达到目的,这无疑会造成极大的浪费现象。而借助于差量更新机制后就可以做到仅仅针对那些确实发生了改变的地方作出相应修正动作而已[^5]。 例如,在列表渲染过程中,即使只有少数几条记录有所变动,也不必重新生成全部项目再插入回去,而是精确找到对应位置实施局部刷新即可完成任务。 --- #### 2. **避免全局重绘与回流** 每当修改了一个可见范围内部任意一处样式特征时都会引起浏览器重新评估布局尺寸以及绘制顺序等一系列连锁反应。然而凭借预先构建好的映射表单形式存储下来的信息作为参照依据的话就能够大幅度削减此类额外负担的发生几率[^1]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值