比较两个新的和旧的虚拟DOM树时,您始终需要根据虚拟DOM的层次结构进行遍历
在上面的代码中,当响应数据文本值更改时,最有效的更新方法是
传统的差异算法不能如此高效。当文本值更改时,将生成一个新的虚拟DOM树。
可以发现,有许多毫无意义的比较操作。
总结:
传统的DIFF算法无法避免旧虚拟DOM树之间无用的比较操作,因为它在运行过程中没有足够的关键信息,因此它无法区分动态内容和静态内容。在运行时区分动态内容和静态内容,您可以实现极简主义的优化策略
例如:
仅{{bar}}是一个动态内容。
可以发现虚拟节点具有附加属性,即patchflag(补丁标志)。如果属性存在,则被认为是动态节点
PatchFlag(补丁徽标)可以理解为一系列数字标记,这意味着如下
它可以从虚拟节点的创建阶段中的动态节点中提取,并将其存储在虚拟节点的动态基阵列中。
渲染器的更新操作将基于块。当渲染器更新一个块时,它将忽略虚拟节点的儿童数组,直接找到DynamicChildren数组,并且仅更新数组中的动态节点。并且仅更新动态内容。在同一时间,由于相应的补丁标志,也可以实现目标更新。
什么是块节点:
在编译器生成的渲染函数代码中,它将不直接包含用于描述虚拟节点的数据结构。相反,它将包含辅助函数来创建虚拟DOM节点,如下
CreateVnode的返回值是虚拟DOM节点
例如:
模板上方具有补丁符号的渲染函数如下:
如何将根节点变成一个块,如何将动态子节点收集到块的动态循环阵列中?
可以发现,在渲染函数中,createvnode函数的调用是嵌套结构层。执行顺序是,执行外部createvnode函数时,已经执行了内部层中的createvinde函数。因此,为了启用外部块节点来收集内部动态节点,需要内部层的动态节点数据到达时。代码实现如下:
然后调整createvnode函数
然后调整
传统的节点更新方法如下:
优化的更新方法,直接比较动态节点
有相应的补丁标志,可以完成针对目标的目标更新
除了模板的根节点外,具有结构指令的节点,例如:v-if,v-for,也应为块。
假设只有最外面的DIV标签将用作块,那么变量foo的值是真或错误,并且块收集的动态节点是相同的,如下:
这意味着它将不会在差异阶段进行更新。明显地,在foo的不同值下,一个是部分,另一个是div,是一个不同的标签,需要更新。
另一个示例:
同样会导致更新失败
问题是:
解决方案:如下所示
在差异过程中,渲染器使用新块根据钥匙值替换旧块。
带有V-FOR指令的节点也将使虚拟DOM树不稳定
例子:
列表的价值从[1,2]变为[1]
更新之前和之后的相应块树如下:
更新前后,动态节点的数量不一致
解决方案:V-FOR指令的标签也被用作块角色,以确保虚拟DOM树具有稳定的结构,无论在运行时V-FOR如何变化。
由于V-For指令呈现片段,因此用于片段
发现片段本身收集的动态节点的存在是不稳定的,这是不稳定的
这种情况不能直接针对
解决方案:撤退到传统虚拟DOM的DIFF方法,即使用碎片的孩子
Fragment的子节点仍然可以是一系列块
当Fragment的子节点更新时,可以还原优化模式
有稳定的片段吗?如下:
稳定的片段,您可以使用优化模式
VUE3模板中的多个根节点也是稳定的片段
减少在更新期间创建虚拟DOM带来的性能费用和内存职业
喜欢:
当没有静态促销时,渲染函数是:
响应数据标题更改后,将重新执行整个渲染函数
将纯静态节点促进渲染函数
更改响应数据后,您将不重新创建静态虚拟节点
包含动态绑定本身的节点将无法改善,但是可以改进节点上的静态属性
它可以减少通过虚拟DOM和内存职业创建产生的费用
基于静态改进,进一步采用了前屈球优化。
在使用静态改进优化策略之后
使用前屈服将这些静态节点序列化为字符串,并生成静态类型Vnode
优势:
每次渲染时,都会为COM组件创建一个新的Props对象。在同一时间,Props对象中的OnChange属性的值也将是一个新函数。导致其他性能开销
V型可以缓存虚拟DOM
由于节点是缓存的,因此意味着更新之前和之后的虚拟节点不会更改,因此这些缓存虚拟节点需要参与差异操作。汇编结果如下:
v-once软件包的动态节点不会由父块收集,因此它们不会参与DIFF操作
V-once带来的性能提高
原始:https://juejin.cn/post/7101859824203202568