Vue 3 的运行机制可以从「宏观 → 微观」做三级拆解:

  1. 应用级(createApp 做了什么)
  2. 组件级(一次渲染的生命周期)
  3. 响应式级(数据变化如何驱动 DOM 更新)

下面按时间线梳理整个执行链路,并穿插源码入口、关键概念和优化点,帮助你把零散的知识点串成一条线。


一、应用级:从 createApp 到挂载

  1. createApp

    import { createApp } from 'vue'
    const app = createApp(App)
    
    • 入口文件:packages/runtime-dom/src/index.ts 中的 createAppAPI(render)
    • 内部:先生成一个应用上下文对象(包含全局配置、全局组件、指令、插件等),再返回 app 实例。
  2. app.mount

    app.mount('#app')
    
    • 把根组件编译成 VNode(首次编译走 runtime-compiler,运行时模板走 runtime-only)。
    • 调用 render(vnode, container) → 进入组件级渲染流程。
    • 挂载完成后,触发根组件的 onMounted 钩子。

二、组件级:一次完整的渲染生命周期

  1. 首次挂载

    1. 解析组件选项
      • 如果是单文件组件(SFC),@vue/compiler-sfc 将其编译成 render() 函数 + 静态提升信息。
    2. 创建组件实例
      • packages/runtime-core/src/component.ts 中的 createComponentInstance 生成一个内部实例(instance)。
    3. 初始化响应式系统
      • 调用 setup()(或 data())得到原始数据,交给 reactive()/ref() 包装成 Proxy。
    4. 编译 render 函数
      • 模板 → render 函数(compiler-core)。编译时做「静态提升」「patchFlag 标记」等优化。
    5. 生成 VNode
      • 执行 render 函数得到 VNode 树。
    6. Diff & Patch
      • packages/runtime-core/src/renderer.tspatch() 递归对比新旧 VNode。
      • 首次无旧节点,直接 mount:调用 DOM API 创建元素、插入父容器。
    7. 绑定生命周期
      • 依次触发:beforeMountmounted(此时 DOM 已生成,可访问 $el)。
  2. 状态更新

    1. 用户代码修改响应式数据 → Proxy setter 触发 trigger()
    2. scheduler 把副作用(组件的渲染 effect)推入微任务队列(Promise.then / MessageChannel)。
    3. 在一次事件循环末尾,调度器按批处理方式重新执行渲染 effect。
    4. 重新执行 render → 得到新的 VNode。
    5. 再次进入 patch:
      • 使用「双端 Diff + 最长递增子序列」算法,最小化 DOM 操作。
      • patchFlag 的节点做靶向更新(class、style、text 等)。
    6. 触发 beforeUpdate → DOM 更新 → updated
  3. 卸载

    • app.unmount() 或路由切换 → 触发 beforeUnmount → 递归清理子组件、指令、事件监听器 → unmounted

三、响应式级:数据变化怎样精确驱动 DOM

  1. 核心对象

    • effect(fn):把 fn 变成响应式副作用。
    • track(target, key):在 getter 中收集依赖(把当前 effect 存进 depsMap)。
    • trigger(target, key):在 setter 中通知所有 effect 重新执行。
  2. 调度器(scheduler)

    • 默认异步批处理:多次同步修改只会触发一次更新。
    • 支持 nextTick() 把回调推迟到 DOM 更新之后。
  3. 优化策略

    • 编译时静态提升(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 setter
         trigger() → scheduler → effect()
              │
              ▼
         patch → DOM diff → beforeUpdate → updated

一句话总结

Vue 3 的执行逻辑是:
createApp 生成应用上下文 → 组件编译成带优化标记的 VNode → Proxy 拦截数据变化 → 调度器批量触发副作用 → Diff 算法靶向更新 DOM → 生命周期钩子串联整个流程。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐