基于虚拟DOM的Diff更新算法研究与优化
在传统的Diff算法中,需要新虚拟DOM树的每一个节点和旧虚拟DOM树的每一个节点进行跨级比较,时间复杂度高达On3,导致页面渲染时间过长。Vue2对传统的Diff算法进行了算法改进,提出利用静态节点约束比较流程,将时间复杂度降低到On,降低了页面渲染时间。但Vue2中选取静态节点的算法复杂,若DOM节点过多,Diff差异比较时间延长,页面渲染时间反而更长
此针对可视化页面数据渲染延迟的问题,在Vue2算法的基础之上,提出了基于虚拟DOM的Diff差异更新优化算法。通过引入key策略和静态检测算法,使得Diff过程只查找树与树之间的动态节点差异,而静态节点直接复用,进一步优化Diff过程
- 利用关键key进行同类静态节点关系标注
- 在页面渲染时建立Map映射关系,利用静态检测算法提取固定节点进行静态保存,提取动态节点进行Diff算法比较
- 将优化后的Diff算法与传统的Diff算法、Vue2的Diff算法做实验仿真比对,以验证本文所优化的Diff算法的有效性
虚拟DOM树
不过多赘述

传统的Diff差异更新算法
在传统的以虚拟DOM为检测对象的Diff(Difference)差异算法中,使用递归的方式从新旧虚拟DOM中的根节点开始,查找树与树之间的所有节点差异
新虚拟DOM树的每一个节点需和旧虚拟DOM树的每一个节点进行跨级比较。由于进行了跨级别的比较,因此遍历完成时算法的时间复杂度达到On2。当差异对比完成,还需计算最小转换方式,最后时间复杂度达到On3之高。若节点嵌套大量子节点,子节点又嵌套大量孙节点,显然整体遍历和计算下来性能消耗量非常大
为降低时间复杂度,Vue结合Snbbdom虚拟DOM库对传统的Diff算法做出了一定的优化:不直接进行跨级比较,而实行同级节点相互比较的机制将算法复杂度降为On。通过Vue结合snabbom对Diff算法的跨级节点到同级节点的优化,使得Diff算法的性能数倍的提高
Diff差异更新算法优化
关键key策略设计
在进行Diff算法之前,为每个节点创建并绑定一个唯一的标志key。使得可以更加快速且精准的找到相同节点,以便进行属性更改、位置移动、创建和删除操作。同时为了使得key更加高效,选择数值型或者字符串型作为唯一的标志,而不使用数组中的Index。若使用index作为key值,这时节点间可能会错位找到自身对应的key,破坏节点操作顺序。数据错位后,不能正确识别key的节点都会被重新创建
基于key的Diff差异更新算法设计
使用newVDomTree表示新虚拟DOM树,oldVDomTree表示旧DOM树。当页面中大屏组件被创建后,该组件所依赖的属性有数据变动时,会运行updateComponent方法。在运行updateComponent时,调用render函数生成新的虚拟DOM树。接着调用update方法,将render函数生成的新虚拟DOM树传入update方法。同时在update方法内调用已存在的旧虚拟DOM,和新虚拟DOM进行同级patch方法比对,最终完成真实的大屏组件更新

基于key的静态检测算法设计
页面初次渲染之后,会得到一个对应真实DOM的虚拟DOM树。组件数据变化时render函数生成新的虚拟DOM树,通过Diff算法比较新旧虚拟DOM树之间的差异,将所得出的精准差异更新到对应的真实DOM上。在组件数据变化时,Diff算法的节点比较会从新旧虚拟DOM的根节点从上而下进行递归比较。然而当组件含有复杂的父子和兄弟关系,且数据进行多次变化时,则会多次调用patch方法进行Diff比较。每一次都会依次从新旧虚拟DOM的根节点从上而下进行递归比较,但是有些静态节点页面上固定的静态数据例如固定的text节点也会每次被Diff算法比较。无疑这种比较是冗余的,这种每次冗余比较堆叠而成的几毫秒,最终会造成虚拟DOM效率逐渐缓慢
使用Mapkey->value建立key和节点之间的关系,在montedVue挂载阶段生命周期对虚拟DOM树使用静态检测算法。将已经标记为静态的节点放入staticMapkey->value,将未标记为静态的节点放入dynamicMapkey->value。从而Diff算法无需再次比较页面上静态节点staticNode,只专注于比较dynamicMap内的动态节点dynamicNode。使得Diff算法可以更加迅速的判断需要变化的内容

静态检测下的Diff算法优化
在Diff算法比较之前增加key策略和静态检测算法。建立staticMapkey->value静态节点映射关系和dynamicMapkey->value动态节点映射关系。使得新旧虚拟DOM树可以只比较动态变化的节点,直接复用固定的静态数据。进一步增快了Diff算法的比较过程,使得变动的差异数据以更快的速度呈现在页面上
