Vue3是如何升级虚拟DOM模块的?
静态标记(PatchFlag)
在Vue2中,元素的更新比较是采用的全量对比的方式,虽然借鉴了react的diff算法中同级对比的方式进行了优化,但依然会对比部分静态节点,这明显还有优化空间。
所以在Vue3中采用了静态标记(PatchFlag)的方式对这部分进行优化。在render函数中就将每个节点进行分析,为动态节点进行标记,标明该节点是未来有可能变化的节点(即动态节点);并且PatchFlag枚举定义了十几种类型,更精确的定位需要对比节点的类型。
现有如下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)均发生了变化。
Vue2的Diff算法采用全量对比的方式:顶层对比一次,第二层对比三次,底层对比六次,共对比10次,结果是找到了3个需要更新的节点。
而Vue3在创建render函数时就将上图中3个未来可能会发生变化的节点进行了对应的静态标记,所以在视图更新时Diff算法仅对比底层的3个红色节点,就找到了全部的3个需要更新的节点。
静态提升(hoistStatic)
Vue3在创建render函数时,会将函数内的静态变量提到render函数外,这也意味着这些静态变量不再参与响应式逻辑(因为它们是常量,永远不会变化,所以能用const时就要用const)。
事件监听缓存(cacheHandler)
事件监听缓存是针对于有事件绑定的节点在Diff算法上的优化,因为在正常开发中,节点上的@click
等事件是不会随着数据变化而变化的,所以在Vue3中哪怕静态节点上绑定了@click
等事件,DOM更新时Diff算法也不会去比较该静态节点。
比如如下节点:
<div @click="submit">提交</div>
该节点在vue2中每次都会参与Diff比较,因为它有@click
绑定,但事实上任何数据变了也不会影响submit
函数,所以最好的情况就是将该节点看做一个静态节点,然而,vue3就是这样做的!Vue3会将该节点看做一个静态节点,永远不会参与Diff算法的比较。