Vue3是如何升级虚拟DOM模块的?

本文详细解析了Vue2和Vue3在处理数据变化时的DOM更新流程及优化策略。Vue2中,当数据变化时,会创建10个vnode并进行10个节点的Diff;Vue3则通过静态节点复用、补丁标志和树扁平化等优化,只需创建7个vnode,比较7个节点,提升了性能。关键优化包括静态节点提升、补丁标志和事件监听缓存,降低了DOM操作成本。

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

现有如下DOM结构:

<div class="message">
    <div class="time">
        <p>时间:</p>
        <p>{{time}}</p>
    </div>
    <div class="position">
        <p>地点:</p>
        <p>{{position}}</p>
    </div>
    <div class="name">
        <p>人物:</p>
        <p>{{name}}</p>
    </div>
</div>

对应的DOM树为:

蓝色的为静态节点,红色的为动态节点。

假设现在触发了一次数据变化,上述DOM结构中三个变量(time、position、name)均发生了变化。

(注:

  • VDOM——虚拟DOM
  • render函数——渲染函数
  • vnode——虚拟节点)

Vue2的整体处理流程:

  1. Template模板编译为render函数
  2. 根据render函数创建VDOM
  3. VDOM渲染为真实的DOM
  4. 当数据发生变化后需要更新DOM时,vue会根据新的DOM结构创建新的VDOM来和现有的VDOM来比较,共需创建10个vnode,实际创建10个vnode
  5. 然后采用Diff算法比较新旧VDOM,判断需要变化的地方。使用同级比较来降低复杂度,最终比较了10个节点(1+3+6),发现了3个需要更新的节点
  6. 更新这三个节点

Vue3的整体处理流程:

  1. Template模板编译为render函数,该过程有如下几点优化。
    • 静态节点复用:此时会将静态节点(如上例中的3个P.label)从render函数中提升出来,并在每次渲染时重用相同的静态节点。此外,当有足够多的连续静态元素时,它们将被压缩成一个“静态 vnode”,其中包含所有这些节点的纯 HTML 字符串(示例)。这些静态 vnode 是通过直接设置挂载的innerHTML。它们还在初始挂载时缓存其对应的 DOM 节点 - 如果在应用程序的其他地方重复使用相同的内容,则使用 native 创建新的 DOM 节点cloneNode(),这非常有效。
    • 补丁标志:每个节点都会标明补丁标志(一个数字),补丁标志代表节点的更新类型,即后续该节点如果变化,会怎样变化,需要如何处理。Vue3内部有很多补丁标志,每个补丁标志对应着不同的处理逻辑,有助于vue更精准快速的更新节点。使用补丁标志,Vue 能够在使用动态绑定更新元素时​​做最少的工作。
  2. 根据render函数创建VDOM,该过程有如下优化。
    • 树扁平化VDOM树的根是使用特殊createElementBlock()调用创建的“块”,每个块跟踪具有补丁标志的任何后代节点(不仅仅是直接子节点)。所以当该组件需要重新渲染时,它只需要遍历扁平化的树而不是完整的树。它大大减少了虚拟DOM协调过程中需要遍历的节点数量。模板的任何静态部分都被有效的跳过。
  3. VDOM渲染为真实的DOM
  4. 当数据发生变化后需要更新DOM时,vue会根据新的DOM结构创建新VDOM来和现有的VDOM来比较。在创建新VDOM时会复用render函数中提升出来的静态节点,所以共需创建10个vnode,复用了3个vnode,所以实际创建了7个vnode
  5. 比较新旧VDOM,判断需要变化的地方,最终比较了7个节点,发现了3个需要更新的节点,该过程有如下优化。
    • 同级比较:使用同一层级的节点来进行比较,以降低复杂度。Vue2也是这样做的。
    • 跳过相同节点:然后当渲染器注意到旧vnode和新vnode是同一个时(复用的静态节点)会直接跳过比较
    • 事件监听缓存:事件监听缓存是针对于有事件绑定的节点在Diff算法上的优化,因为在正常开发中,节点上的@click等事件是不会随着数据变化而变化的,所以在Vue3中哪怕静态节点上绑定了@click等事件,DOM更新时Diff算法也不会去比较该静态节点。如:<div @click="submit">提交</div>。该节点在vue2中每次都会参与Diff比较,因为它有@click绑定,但事实上任何数据变了也不会影响submit函数,所以最好的情况就是将该节点看做一个静态节点,然而,vue3就是这样做的!Vue3会将该节点看做一个静态节点,永远不会参与Diff算法的比较。
  6. 根据需要更新的三个节点的补丁标志进行定制化更新节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值