前言
Svelte和SolidJS的兴起重新非虚拟DOM框架的模式引入公众视野。到2024,虚拟dom好像被市场尝试慢慢抛弃,Vue正在构建无虚拟dom的版本…..
虚拟dom
优点
HTML 模板的高度抽象。受限于 html 语法限制,我们难以复用 HTML 节点;而使用 Virtual DOM,我们能够用 JS 描述 DOM 节点,从而带来了复用 HTML 模板的能力,提高效率。
跨平台。抽象出了 Virtual DOM 数据结构后,就可以适配 DOM 之外的渲染目标,如移动端(Weex)。
现代前端科技解析 —— Virtual DOM - 404Forest
- 利用虚拟dom,可以将一些html的属性抽象成js属性,减少对对真实dom的读取或操作,从而提升性能。对JS的操作比dom的操作会更加灵活和拓展性更强
- uniapp等跨平台框架实现的核心。
缺点
首次渲染性能低,第一次需要全量构建虚拟dom。
运行时内存占用大,需要维护一份虚拟dom tree的内存副本。
生成虚拟dom所需的成本。
VUE与虚拟dom
生成时机
vue利用parser将template转成AST,然后经过优化,而后通过代码生成器生成render函数,执行生成虚拟dom。而后通过数据更换和监测,传入数据可生成实时的虚拟dom,进行patch->diff后生成dom。
数据结构
本点以下内容复制来自现代前端科技解析 —— Virtual DOM - 404Forest
本文实现的 Virtual DOM 参考 Vue,结构简化,如下:
interface VNode { type?: 'Element' | 'Text' | 'Comment', tag?: string, data?: VNodeData, children?: Array<VNode>, text?: string, elm?: Node } interface VNodeData { key?: string, ref?: string, events?: { [key: string]: any }, attrs?: { [key: string]: any }, rawAttrs?: { [key: string]: any }, directives?: { [key: string]: any } }
|
template到render
转换前:
<div class="container"> <!-- test --> <button v-on:click="clickHandler">click me</button> <ul :class="testClass" v-if="show"> <li v-for="city in arr" >{{city}}</li> </ul> </div>
|
转换后:
function render() { with(this) { return _c('Element', 'div', {attrs: {class: 'container',},events: {},}, [ _s(` `), _m(` test `), _s(` `), _c('Element', 'button', {attrs: {},events: {click: clickHandler},}, [ _s(`click me`) ]), _s(` `), (show) ? _c('Element', 'ul', {attrs: {class: testClass,},events: {},}, [ _s(` `), ...(() => { return arr.map(city => { return _c('Element', 'li', {attrs: {},events: {},}, [_s(city)]) }) })(), _s(` `)]) : _e(),_s(` `) ]) } }
|
创建真实dom
function createDOM(node: VNode) { let $node: Node if(node.type === 'Element') { $node = document.createElement(node.tag) node.children.forEach(e => { $node.appendChild(createDOM(e)) }) updateProps($node, node.data.attrs, {}) updateEvents($node, node.data.events, {}) } if(node.type === 'Text') { $node = document.createTextNode(node.text) } if(node.type === 'Comment') { $node = document.createComment(node.text) } node.elm = $node return $node }
|
发展历程
Vue1.0的时候还是真实dom,Vue2.0去除了运行时的 HTML Parser,全面拥抱虚拟dom,Vue3.0又在尝试剥离虚拟dom,推出了Vue的蒸汽模式(Vapor Mode)。
Vue next–Vapor Mode
vuejs/core-vapor: Vue Vapor (no virtual DOM) Experimental repo. (github.com)
- 一个全新的编译策略
- 相同的模板语法,但编译后的代码性能更高。
- 利用 Template标签克隆元素 + 更精准的绑定,并且没有虚拟 DOM
只支持 Composition API 和带有<script setup>
的 .vue 文件
在应用级别,使用 Vapor Mode 编译的应用能够完全移除虚拟DOM运行时,只包含极简轻量的 @vue/reactivity 和 vapor 模式运行时辅助代码。这样一个应用的基础大小只有约6kb,相比目前含虚拟DOM的 Vue 3 应用的约50kb,缩减了88%。
即将到来的 Vue 3 “Vapor Mode” - 知乎 (zhihu.com)

参考
现代前端科技解析 —— Virtual DOM - 404Forest
即将到来的 Vue 3 “Vapor Mode” - 知乎 (zhihu.com)