Vue 3 的运行机制
Vue 3 的运行机制可以从「宏观 → 微观」做三级拆解:
- 应用级(createApp 做了什么)
- 组件级(一次渲染的生命周期)
- 响应式级(数据变化如何驱动 DOM 更新)
下面按时间线梳理整个执行链路,并穿插源码入口、关键概念和优化点,帮助你把零散的知识点串成一条线。
一、应用级:从 createApp
到挂载
-
createApp
import { createApp } from 'vue' const app = createApp(App)
- 入口文件:
packages/runtime-dom/src/index.ts
中的createAppAPI(render)
- 内部:先生成一个应用上下文对象(包含全局配置、全局组件、指令、插件等),再返回
app
实例。
- 入口文件:
-
app.mount
app.mount('#app')
- 把根组件编译成 VNode(首次编译走 runtime-compiler,运行时模板走 runtime-only)。
- 调用
render(vnode, container)
→ 进入组件级渲染流程。 - 挂载完成后,触发根组件的
onMounted
钩子。
二、组件级:一次完整的渲染生命周期
-
首次挂载
- 解析组件选项
- 如果是单文件组件(SFC),
@vue/compiler-sfc
将其编译成render()
函数 + 静态提升信息。
- 如果是单文件组件(SFC),
- 创建组件实例
packages/runtime-core/src/component.ts
中的createComponentInstance
生成一个内部实例(instance
)。
- 初始化响应式系统
- 调用
setup()
(或data()
)得到原始数据,交给reactive()
/ref()
包装成 Proxy。
- 调用
- 编译 render 函数
- 模板 → render 函数(compiler-core)。编译时做「静态提升」「patchFlag 标记」等优化。
- 生成 VNode
- 执行 render 函数得到 VNode 树。
- Diff & Patch
packages/runtime-core/src/renderer.ts
的patch()
递归对比新旧 VNode。- 首次无旧节点,直接 mount:调用 DOM API 创建元素、插入父容器。
- 绑定生命周期
- 依次触发:
beforeMount
→mounted
(此时 DOM 已生成,可访问 $el)。
- 依次触发:
- 解析组件选项
-
状态更新
- 用户代码修改响应式数据 → Proxy setter 触发
trigger()
。 scheduler
把副作用(组件的渲染 effect)推入微任务队列(Promise.then / MessageChannel)。- 在一次事件循环末尾,调度器按批处理方式重新执行渲染 effect。
- 重新执行 render → 得到新的 VNode。
- 再次进入 patch:
- 使用「双端 Diff + 最长递增子序列」算法,最小化 DOM 操作。
- 有
patchFlag
的节点做靶向更新(class、style、text 等)。
- 触发
beforeUpdate
→ DOM 更新 →updated
。
- 用户代码修改响应式数据 → Proxy setter 触发
-
卸载
app.unmount()
或路由切换 → 触发beforeUnmount
→ 递归清理子组件、指令、事件监听器 →unmounted
。
三、响应式级:数据变化怎样精确驱动 DOM
-
核心对象
effect(fn)
:把 fn 变成响应式副作用。track(target, key)
:在 getter 中收集依赖(把当前 effect 存进 depsMap)。trigger(target, key)
:在 setter 中通知所有 effect 重新执行。
-
调度器(scheduler)
- 默认异步批处理:多次同步修改只会触发一次更新。
- 支持
nextTick()
把回调推迟到 DOM 更新之后。
-
优化策略
- 编译时静态提升(hoistStatic):把不变节点提到渲染函数外,减少每次 diff 成本。
- PatchFlag:为动态节点打标记,diff 时跳过静态部分。
- 缓存事件处理函数(cacheHandlers),避免每次渲染都生成新函数。
- Tree-shakable:未用到的模块在构建阶段被移除。
四、一张时序图帮助记忆
用户代码│├─ createApp(App) ------------┐│ 应用上下文│ 全局API/插件├─ app.mount('#app') --------┐ ││ │▼ ▼首次挂载生命周期┌────────────────────────────────────────┐│ 解析SFC → 编译render → createComponent ││ setup() → reactive() → render() → VNode││ patch → mount → beforeMount → mounted │└────────────────────────────────────────┘│▼用户交互/代码修改 state│▼Proxy settertrigger() → scheduler → effect()│▼patch → DOM diff → beforeUpdate → updated
一句话总结
Vue 3 的执行逻辑是:
createApp 生成应用上下文 → 组件编译成带优化标记的 VNode → Proxy 拦截数据变化 → 调度器批量触发副作用 → Diff 算法靶向更新 DOM → 生命周期钩子串联整个流程。