跳至主要內容

虚拟 DOM

wzCoding大约 4 分钟VueVue3虚拟 DOM

虚拟 DOM

虚拟 DOM 是 Vue 中的一个重要概念,那么什么是虚拟 DOM 呢?简单来说,虚拟 DOM 是一个模拟真实 DOM 属性的普通 JS 对象,它与页面上的真实 DOM 对应,当状态变化页面需要更新时,虚拟 DOM 会通过 diff 算法将更新前后的差异渲染到真实 DOM 上。

虚拟 DOM 的性能

虚拟 DOM 本质上还是一个 JS 对象,最终还是会通过操作真实 DOM 完成页面更新,那么它的性能到底如何呢?

命令式 vs 声明式

在早期页面开发时,我们经常使用命令式的写法来更新页面,例如使用 jQuery 或者原生 JS:

//jQuery 写法
$('#app').text('hello world')

//原生 JS 写法
const app = document.getElementById('app')
app.innerText = 'hello world'

这种命令式的写法目的明确,页面更新渲染通过直接对需要改动的真实 DOM 进行操作,不仅符合逻辑而且也十分直观。

在 Vue 等前端框架出现后,我们更新页面的方式变成了声明式的了,例如:

<div>{{ text }}</div>

//Vue 写法
const text = ref('hello world')

可以看到,声明式的写法只需要声明状态(数据),页面更新渲染通过框架生成的虚拟 DOM 和 diff 算法计算得到最终结果,然后替我们操作真实 DOM 完成更新。这种写法十分简洁,省去了我们获取真实 DOM 的过程

实际性能

从上面的例子可以看出:

  • 命令式更新页面消耗的性能 = 直接操作真实DOM消耗的性能
  • 声明式更新页面消耗的性能 = JS计算消耗的性能(diff 算法) + 直接操作真实DOM消耗的性能

在一般情况下,相比于声明式的通过状态更新页面,命令式直接操作真实 DOM 来更新页面似乎性能消耗更小。

在真实的页面开发中,使用命令式的写法来更新页面时,当状态发生变化后,我们可能无法精确的找到对应的真实 DOM 进行操作,往往会对整个 DOM 进行更新(例如使用 innerHTML),这样做似乎也会造成不必要的性能消耗。使用声明式的写法更新页面时,可以通过 diff 算法来找出更新前后的差异,精确的找到要更改的真实 DOM 进行操作,这样看起来性能也还可以接受。

由以上分析可以得出结论:声明式写法的性能不一定好于命令式(即虚拟 DOM 的性能不一定好于直接操作真实 DOM)

为什么需要虚拟 DOM

如果虚拟 DOM 的性能不一定好于直接操作真实 DOM,那么为什么 Vue 还是使用了虚拟 DOM 呢?

框架设计

Vue 框架在设计时不仅需要考虑到框架性能的问题,也要兼顾许多其他方面的问题。例如支持跨平台:Vue 作为一个通用框架,它不仅要考虑到在浏览器环境下使用,也可能会在 app、桌面应用等环境下使用,而真实 DOM 是浏览器环境下特有的,采用虚拟 DOM 就很好的避免了这种情况,通过虚拟 DOM 计算出最终要更新渲染的结果,再由操作不同环境下的 UI 接口将结果渲染到页面,从而为跨平台提供了良好的支持。

性能保证与可维护性

虚拟 DOM 可以通过框架内部的算法来精确找到更新前后的差异部分从而做到精确的渲染,通过 JS 计算与精确的 DOM 操作来使更新的性能消耗达到最小化,在一定程度上保证了页面更新消耗性能的下限。同时它使我们在更新页面时只用关心状态的变化从而降低了我们开发时的心智负担,避免了大量的操作真实 DOM 从而提升了代码的可维护性。虚拟 DOM 是由此权衡而出的选择。