Vue vs React 虚拟DOM哪家强?

前言

时至今日,前端框架已经步入了稳定的成熟期,Vue React二分天下,虽然网上诸多争论,但客观讲现在确实没办法明确的分出好坏,因为他们有着各自的用户群体,代表着他们各自的设计理念大相径庭,哪种设计思想能掌握未来呢,只能留待时间的考证。

但是呢,好的设计,即使设计理念大相径庭,但实现细节也会殊途同归,时间来到了2023年,一个好的框架应该是什么结构,已经有一个很明确的范式了,比如

  • 生命周期
  • 组件化
  • 响应式
  • 虚拟DOM
  • 单向数据流
  • state 组件&全局状态
  • 渲染函数
  • ........

虚拟DOM

本文将着重讲述下虚拟DOM,这已经是一个老生常谈的话题,大量的文章讲述虚拟DOM的细节,因为本文旨在对比分析 Vue React 两门框架,所以按理应该讲述下两门框架中对于虚拟DOM实现上的差别。

但其实这是一个很无聊的过程,双方的实现细节隐藏在各自源码中,阅读源码是一件费时费心费力的事情,对于前端开发者来讲,框架是如何做的 Dom diff ,用的树还是用的链表、用的什么算法,都没有感知,即使你真的从头到尾认真看一遍,让你对框架的理解也不会有太大提升,而且你现在看了一遍,下个迭代版本他们逻辑又换了。个人感觉这部分源码复杂多变,对于理解框架本身的意义不是很大。

你只需要理解无论是 Vue 还是 React,对于 虚拟DOM 所做的事就是:

基于自身的设计带来的框架能力 在虚拟DOM中做相应的注入 ,再通过策略+算法 ,最终在性能 or 速度中寻找各自的最佳平衡点。

  • 框架能力

    Vue 采用 template 固定模板提供开发 HTML 的能力,通过自定的语法(如指令),在编译阶段即可拿到一份【充满信息标注】的模板字符串,在生成渲染函数时,可以通过这些信息做更加详尽、更有针对性的渲染优化。而 React 直接采用开发函数组件的方式直接输出渲染函数,在虚拟DOM渲染时,自然可利用的信息更少,这就是框架自身的设计带来的不同框架能力

  • 策略 + 算法

    具体到虚拟DOM要真正渲染时,所谓的 DOM diff 过程是复杂的,具体可分为两个层面,第一是核心的 diff 算法,而现在实现 diff 通常是多个算法组合使用,将时间复杂度降为O(n);其次是更新策略,比如对于当前已经变更的子节点是直接替换,还是再深入的比对更深层的子节点,框架开发者会有自己的考量

  • 性能 or 速度

    无论框架开发者制定什么策略,对于渲染过程中的 DOM diff 需要考量的无非是性能速度,不考虑时间复杂度,diff 算法能算出极致渲染性能的渲染函数,但同时渲染前的计算时间会被大大拉长;同样如果要将 diff 复杂度降为 O(n) 甚至更短,那浏览器就要付出更多的渲染成本。

如何给最快的给用户呈现出页面,框架开发者需要再诸多影响变量中,寻找一条他认为性价比最高的一条路。

Vue 模板的优势

很多人都说 Vue 模板看起来太死板了,设计思想偏传统,远不如 React 大胆、颠覆、优雅,我相信很多开发者是被 React 优雅的函数式编程、简洁颠覆的设计思想、极度灵活的开发方式所吸引,但这里就需要着重提一下 Vue 模板所带来的好处了。

静态分析

上文已经简单说过了,Vue 通过自定的模板语法,固定的写法,在模板中留下大量的信息标注,经过静态分析,这些有价值的标注将附加在模板字符串,虚拟DOM中,在整个编译时,运行时带来很多可优化的可能。

静态提升

html 复制代码
<div>
  <div>foo</div> <!-- 需提升 -->
  <div>bar</div> <!-- 需提升 -->
  <div>{{ dynamic }}</div>
</div>

以上是官网实例,表明在没有变量引用的纯静态dom "foo" "bar" 会在编译阶段直接提升渲染函数之外,作为一份不可变的"常量",在 DOM diff 时会问完全跳过对比,当遇到连续多个静态节点时,还会被压缩成一个静态 Vnode 直接通过 innerHTML渲染到页面,并缓存下来,如果有其他地方复用一样的静态节点,使用原声的cloneNode方法克隆新 DOM 节点,非常高效。

类型标记

html 复制代码
<!-- 仅含 class 绑定 -->
<div :class="{ active }"></div>

<!-- 仅含 id 和 value 绑定 -->
<input :id="id" :value="value">

<!-- 仅含文本子节点 -->
<div>{{ dynamic }}</div>

对于动态绑定的元素,在编译时推断出相应的类型,在生成渲染函数时,标注上该类型,运行时根据类型做不同的渲染逻辑

VDOM 树变数组

将传统树形结构,打散成一个个区块,每个区块是一个稳定的 vnode 组合,在区块内部将所有后代节点标记出那些是静态节点,那些需要动态追踪,最终将一个区块输出成一个数组。如下代码

html 复制代码
// 区块1
<div v-if> 
  <div>aaaaa</div>      <!-- 不会追踪 -->
  <div>{{ bar }}</div>  <!-- 要追踪 -->
  <div :id="id"></div>  <!-- 要追踪 -->
</div>
// 区块2
<div v-else>
</div>

当这个区块内有内容需要重新渲染时,只需要遍历该数组,所有静态部分会被高效的略过。

虚拟DOM 常见误区

误区:虚拟DOM渲染比真实DOM渲染更快

认为虚拟DOM会更快是最常见的误区之一,但这是不一定的,或者说这两者本身就没有必然的联系。

所谓的虚拟DOM,就是在真实DOM前做用js对象一层映射,当有变动改变页面渲染时,先改变虚拟DOM,再通过虚拟DOM找到需要渲染的最小DOM元素,所以如果只从表面上看,那么直接操作真实DOM变更应该是更快的。

  • 真实DOM:内容改变------>真实DOM更新
  • 虚拟DOM:内容改变------>虚拟DOM------>DOM diff------>真实DOM更新

虽然 js 对象的操作和计算是很便宜的,但虚拟DOM会无故增加维护虚拟DOM对象和 diff 过程,肯定是增加了渲染前的计算时间的,没有什么是比直接操作DOM去改变内容最快的了

有些人的想法是:虽然手动操作DOM很快,但多数情况开发者对于数据改变,触发页面重新渲染,都只是 innerHTML一把梭,造成了大量的渲染浪费,而渲染是远比计算昂贵的操作。

没错,传统开发方式的确会有渲染浪费的问题,但很难说接入虚拟DOM后一定会是:增加的 js 计算时间 < 节省的渲染时间,所以虚拟DOM渲染比真实DOM渲染更快是一个错误的结论。

正确的结论应该是:

  1. 虚拟DOM并不一定会让渲染更快,只能说在大量级的渲染时,可能会让渲染加快,而普通量级时更多的反而会让渲染变慢
  2. 更重要的是接入虚拟DOM后,渲染过程会变的更加稳定,传统的操作DOM方式太过不可控,随着复杂度提升浪费也会无限提升,最终造成严重性能问题,而虚拟DOM中,js的计算是很便宜的事,只要在一个正常的时间复杂度下,计算增加的时间会始终处于一个可控的范围内,大大提高系统的稳定性。

虚拟DOM真正意义

虽然虚拟DOM并不一定能带来性能的提升,但是它对前端框架的发展有着至关重要的意义:

  • 完美的掩盖了DOM的底层操作,始终以最小代价更新视图
  • 框架的开发者可以面对 js 对象开发,极大的降低了复杂性

最重要的是,虚拟DOM可以让前端代码真正脱离端,真正实现多平台的可移植性,只需要我们再开发一份虚拟DOM和新平台UI渲染的映射关系,这简直为前端未来的发展奠定了最坚实的路基。

参考文献

相关推荐
拜晨5 分钟前
用流式 JSON 解析让 AI 产品交互提前
前端·javascript
浩男孩8 分钟前
🍀vue3 + Typescript +Tdesign + HiPrint 打印下载解决方案
前端
andwhataboutit?9 分钟前
LANGGRAPH
java·服务器·前端
无限大610 分钟前
为什么"Web3"是下一代互联网?——从中心化到去中心化的转变
前端·后端·程序员
cypking12 分钟前
CSS 常用特效汇总
前端·css
程序媛小鱼16 分钟前
openlayers撤销与恢复
前端·js
Thomas游戏开发17 分钟前
如何基于全免费素材,0美术成本开发游戏
前端·后端·架构
若梦plus19 分钟前
Hybrid之JSBridge原理
前端·webview
chilavert31819 分钟前
技术演进中的开发沉思-269 Ajax:拖放功能
前端·javascript·ajax
xiaoxue..20 分钟前
单向数据流不迷路:用 Todos 项目吃透 React 通信机制
前端·react.js·面试·前端框架