为什么Vue.js中要采用虚拟DOM

1,176 阅读3分钟

Vue.js中采用虚拟DOM的前因后果

引言

在我上一篇笔记Vue.js视图层框架设计-命令式与声明式中谈到Vue.js在视图层框架设计中采用的是命令式内部实现+声明式外部暴露的构建方案,那么就存在一个摆在明面上的问题:选择了尽可能地把声明式暴露给用户,那么对性能必定会有所影响,即声明式代码的更新消耗 = 找出差异的性能消耗 + 直接修改的性能消耗(命令式)。到此,如何尽可能地降低找出差异的性能消耗成为迫切需要解决的问题,Vue.js设计团队给出的方案就是虚拟DOM

什么是虚拟DOM

在前端领域,DOM指的是文档对象模型,是HMTL和XML文档的编程接口,提供了一种对文档的结构化表述。而虚拟DOM简言而之,就是用JavaScript仿照DOM结构实现的一种树形结构对象,如Vue.js官方文档中写明的渲染函数h()就实现了创建虚拟DOM节点的功能,如下:

QQ截图20220223200843.jpg

虚拟DOM与innerHTML的性能比较

创建页面时的性能比较

虚拟DOM

虚拟DOM在创建页面的过程中分为两步:

graph TD
创建JavaScript对象 --> 递归遍历虚拟DOM树并创建真实DOM

用一个公式来表示使用虚拟DOM创建页面的性能:创建JavaScript对象的计算量 + 创建真实DOM的计算量

innerHTML

使用innerHTML创建页面的代码如下:

carbon (9).png

看起来简单吧?可是这段代码的内部实现可没看起来的这么简单。为了渲染出页面,首先要把字符串解析成DOM树,这可是一个DOM层面的计算操作,比纯JavaScript层面的操作要慢上许多。

用一个公式来表示通过innerHTML创建页面的性能:HTML字符串拼接的计算量 + innerHTML的DOM计算量

图表对比

虚拟DOMinnerHTML
纯JavaScript运算创建JavaScript对象(VNode)渲染HTML字符串
DOM运算新建所有DOM元素新建所有DOM元素

可见,从宏观的角度上看,在创建页面时各方法的性能差别不大

更新页面时的性能比较

更新页面是在创建页面的基础上进行选择性的替换

虚拟DOM

  • 重新创建JavaScript对象(虚拟DOM树)
  • 调用Diff算法找到变化的元素并更换

innerHTML

  • 重新构建HTML字符串
  • 重新设置DOM元素的innerHTML属性

图表对比

虚拟DOMinnerHTML
纯JavaScript运算创建新的JavaScript对象+Diff渲染HTML字符串
DOM运算必要的DOM更新销毁所有旧DOM并新建所有新DOM
性能因素与数据的变化量有关与模板大小有关

对于虚拟DOM来说,只需要更新变化的元素,而对于使用innerHTML来说,需要删除所有旧DOM并新建所有新DOM,而且性能上的消耗随模板的增大而越来越大,这时,虚拟DOM的优势就体现出来了。

总结

Vue.js采用虚拟DOM是在各方面平衡的结果,既降低了用户的学习成本与使用成本(写声明式代码),还保证了应用程序的性能下限,让应用程序的性能不至于太差,甚至尽可能地逼近命令式代码的性能

各方案性能由高到低如下:

  • 原生JavaScript(心智负担大、可维护性差、性能高)
  • 虚拟DOM(心智负担小、可维护性强、性能不错)
  • innerHTML模板(心智负担中等、性能差)

声明

  • 本文属于读书笔记一类,是作者在拜读 霍春阳 大佬的新作《Vue.js设计与实现》途中,以书中内容为蓝本,辅以个人微末的道行“填写”完成
  • 欢迎大佬斧正
  • 日更

参考资料