《Vue.js设计与实现》笔记 第1章:权衡的艺术
Vue.js设计与实现 第一章:权衡的艺术
本章导读
Vue.js 并不是单纯追求性能最强或功能最多的框架,而是在多个目标之间寻找最佳平衡点。
Vue 的设计核心思想:
框架设计本质上是一门权衡(Trade-off)的艺术。
主要权衡:
- 声明式 vs 命令式
- 性能 vs 开发效率
- 运行时 vs 编译时
- 灵活性 vs 可维护性
一、命令式与声明式
命令式(Imperative)
命令式编程关注:
如何做(How)
例如:
const div = document.createElement('div')
div.textContent = 'Hello Vue'
div.id = 'app'
document.body.appendChild(div)
开发者需要一步一步描述:
- 创建元素
- 设置内容
- 设置属性
- 插入页面
特点
| 优点 | 缺点 |
|---|---|
| 灵活度高 | 代码量大 |
| 性能可控 | 可维护性差 |
| 能做任何复杂操作 | 开发效率低 |
声明式(Declarative)
声明式编程关注:
做什么(What)
例如:
<div id="app">Hello Vue</div>
或者:
<template>
<div id="app">Hello Vue</div>
</template>
开发者只描述最终结果:
我要一个 div
内容为 Hello Vue
id 为 app
至于如何创建、更新 DOM,由框架负责。
特点
| 优点 | 缺点 |
|---|---|
| 可读性高 | 灵活性略低 |
| 开发效率高 | 存在框架开销 |
| 易维护 | 性能不如极致手写优化 |
为什么 Vue 采用声明式?
例如:
<div>{{ title }}</div>
开发者只关心:
title = 'Vue3'
而不需要关心:
- DOM如何创建
- DOM如何更新
- 哪些节点发生变化
这些工作由 Vue 自动完成。
因此:
Vue 用少量性能损失
换取巨大开发效率提升
二、性能与可维护性的权衡
原生 JavaScript 性能最高
例如:
const div = document.createElement('div')
div.textContent = 'Hello'
因为:
- 没有框架
- 没有虚拟DOM
- 没有运行时分析
执行路径最短。
为什么还需要框架?
因为大型项目中需要解决:
- 状态管理
- DOM更新
- 组件通信
- 生命周期管理
- 路由管理
如果全部手写:
性能高
开发痛苦
维护困难
框架存在的意义
框架帮助开发者:
- 管理状态
- 管理视图
- 管理组件
- 管理更新流程
因此:
牺牲部分运行性能
换取更高开发效率和可维护性
三、虚拟DOM(Virtual DOM)
什么是虚拟DOM
虚拟DOM本质上是:
使用 JavaScript 对象描述真实 DOM。
例如:
const vnode = {
tag: 'div',
props: {
id: 'app'
},
children: 'Hello Vue'
}
这里的 vnode 就是虚拟节点(VNode)。
为什么需要虚拟DOM?
直接操作 DOM 成本较高。
例如:
DOM操作
↓
触发重排(Reflow)
↓
触发重绘(Repaint)
↓
性能开销
Vue 通过虚拟DOM进行优化:
新VNode
↓
Diff比较
↓
找出变化
↓
更新真实DOM
虚拟DOM的优势
1. 跨平台能力
同一套 VNode 可以渲染到:
- 浏览器 DOM
- 服务端 HTML(SSR)
- 小程序
- Native
2. 更好的开发体验
开发者只需要:
<div>{{ count }}</div>
更新数据:
count++
Vue 自动更新视图。
3. 更新优化
通过 Diff 算法:
只更新变化部分
避免全量重建 DOM。
虚拟DOM的缺点
额外开销:
- 创建 VNode
- Diff 比较
- 内存占用
因此:
理论性能:
手写优化DOM
>
虚拟DOM
>
完全重建DOM
四、运行时与编译时
运行时(Runtime)
运行时框架需要在浏览器中执行:
h('div', 'Hello Vue')
生成 VNode。
典型代表:
- Vue 2
- React
编译时(Compile Time)
开发者编写:
<div>Hello Vue</div>
编译器转换为:
render() {
return h('div', 'Hello Vue')
}
编译器的作用
将:
Template
转换成:
Render Function
整体流程:
Template
↓
Compiler
↓
Render Function
↓
VNode
↓
DOM
五、Vue3为什么采用运行时+编译时
Vue3采用:
Runtime + Compiler
同时拥有两者优点。
运行时优势
灵活。
例如:
render() {
return h(...)
}
可以动态生成任意界面。
编译时优势
编译阶段提前分析模板。
例如:
<div>
<span>静态内容</span>
<p>{{ msg }}</p>
</div>
编译器知道:
span 永远不会变
p 会变化
更新时:
只更新 p
无需全量 Diff。
六、Vue3编译优化
这是 Vue3 性能提升的重要来源。
1. Patch Flag(补丁标记)
编译器会标记:
哪些节点可能变化
例如:
<div>{{ msg }}</div>
编译后:
createElementVNode(
'div',
null,
msg,
PatchFlags.TEXT
)
其中:
PatchFlags.TEXT
表示:
只有文本内容会变化
更新时无需完整 Diff。
2. 静态提升(Static Hoist)
例如:
<div>
<span>静态内容</span>
<p>{{ msg }}</p>
</div>
编译器会将:
<span>静态内容</span>
提升到渲染函数外部。
只创建一次。
避免重复创建。
3. Block Tree
Vue3 引入:
Block Tree
用于记录:
动态节点集合
更新时:
只遍历动态节点
而不是:
遍历整棵VNode树
进一步减少 Diff 成本。
七、Vue设计目标
Vue 的设计目标可以总结为三点:
1. 易用性
例如:
<template>
<div>{{ msg }}</div>
</template>
学习成本低。
开发效率高。
2. 高性能
通过:
- 虚拟DOM
- Patch Flag
- 静态提升
- Block Tree
- 编译优化
提升运行效率。
3. 可维护性
通过:
- 组件化
- 响应式系统
- 声明式开发
降低项目复杂度。
高频面试题
什么是声明式编程?
只描述结果,不描述实现过程。
例如:
<div>{{ msg }}</div>
Vue为什么采用声明式设计?
原因:
- 开发效率高
- 可维护性好
- 更符合组件化思想
什么是虚拟DOM?
使用 JavaScript 对象描述真实 DOM。
虚拟DOM一定比原生DOM快吗?
不一定。
性能关系:
手写优化DOM
>
虚拟DOM
>
完全重建DOM
Vue3为什么比Vue2快?
主要原因:
- Patch Flag
- 静态提升
- Block Tree
- 编译优化
减少运行时 Diff 成本。
Vue3为什么同时拥有运行时和编译时?
因为:
运行时 → 灵活
编译时 → 高性能
两者结合能够获得更好的综合表现。
第一章核心知识图谱
Vue设计思想
├── 权衡(Trade-off)
│
├── 命令式 VS 声明式
│ └── Vue选择声明式
│
├── 性能 VS 开发效率
│ └── Vue选择平衡
│
├── 虚拟DOM
│ ├── VNode
│ ├── Diff
│ └── 跨平台
│
├── Runtime
│
├── Compiler
│
└── Vue3优化
├── Patch Flag
├── Static Hoist
└── Block Tree
本章总结
Vue 的设计本质是:
权衡的艺术(Trade-off)。
Vue3 的核心架构:
Template
↓
Compiler
↓
Render Function
↓
VNode
↓
Diff
↓
DOM更新
性能优化来源:
Compiler
├── Patch Flag
├── Static Hoist
└── Block Tree
最终实现:
- 高性能
- 高开发效率
- 高可维护性
这一章的内容是理解整本《Vue.js设计与实现》的理论基础,也是后续学习响应式系统、渲染器和编译器源码的核心前置知识。

浙公网安备 33010602011771号