1116 字
6 分钟
vue的工作流程
2026-03-03
2026-03-04
统计加载中...

vue 的工作流程#

如果你已经握着 Vue 3 最核心的引擎——响应式系统

现在,我们要把这个“引擎”装进车里,看看它是如何配合编译器(Compiler)和渲染器(Runtime/Renderer),让整个 Vue 项目跑起来的。

Vue 的工作流程可以被概括为一个闭环:编译 -> 挂载 -> 响应式更新 -> 补丁 (Diff)

我们用一张逻辑图来把它们串起来:


第一阶段:编译时 (Compile Time) —— “把模版变成代码”#

我们在 .vue 文件里写的 <template>,浏览器是看不懂的。需要编译器把它翻译成 JS 代码。

  1. Parse (解析):把 <div id="app">{{ msg }}</div> 解析成 AST (抽象语法树)

  2. Transform (转换):这是 Vue 3 优化的重灾区。它会分析 AST,标记出哪些是静态节点(永远不变),哪些是动态节点(绑定了响应式数据)。

    • PatchFlags:给动态节点打上标记(比如:这个节点只有 TEXT 变了,或者只有 CLASS 变了)。
  3. Generate (生成):把优化后的 AST 生成为 渲染函数 (Render Function)

产出物: 一个 render 函数。

// 编译后的 render 函数长这样(简化版)
function render(ctx) {
return h('div', { id: 'app' }, ctx.msg)
}

第二阶段:运行时初始化 (Mount) —— “引擎点火”#

这里是响应式系统渲染器第一次握手的地方。

  1. 初始化数据:组件里的 data() 被调用,通过 reactive()ref() 变成响应式对象(就是你写的 Proxy)。

  2. 建立副作用 (Render Effect)

  3. Vue 会创建一个组件级别的副作用函数(类似于你写的 watchEffect)。它的工作是执行 render 函数。

  4. 首次执行 Render

    • 副作用函数开始执行。
    • 调用 render() 函数生成 虚拟 DOM (Virtual DOM / VNode)
    • 关键点来了: 在执行 render 时,读取了 ctx.msg(响应式数据)。
    • 触发 track 响应式系统把这个“组件副作用”收集到了 msg 的依赖桶里。
  5. 挂载 (Patch):渲染器根据生成的 VNode,创建真实的 DOM 节点,插入页面。


第三阶段:响应式更新 (Update) —— “数据驱动视图”#

现在用户修改了数据:this.msg = 'Hello Vue'

  1. **触发 **set:拦截器工作。
  2. 触发 trigger:响应式系统找到 msg 对应的依赖——也就是组件的渲染副作用 (Render Effect)
  3. 调度执行:组件更新逻辑被推入微任务队列(queueJob,就是你学的调度器)。

第四阶段:Diff 算法与 Patch —— “精准手术”#

副作用函数重新执行,这次不是初始化,而是更新

  1. 重新 Render:再次调用 render(),生成一棵新的 VNode 树

  2. Diff (对比)

    • 渲染器拿着 新 VNode旧 VNode 进行对比。
    • 利用编译时的优化:还记得第一阶段的 PatchFlags 吗?如果标记显示只有文本变了,Diff 算法就只对比文本,完全跳过属性对比和子节点对比。
    • 最长递增子序列:如果涉及到列表(v-for)的乱序移动,Vue 3 会用这个算法计算出最小移动次数。
  3. Patch (打补丁):根据 Diff 的结果,只更新变动的那一小块真实 DOM。


特别篇:数据双向绑定 (v-model)#

v-model,它其实不是什么魔法,而是上面流程的一个语法糖组合拳。

<input v-model="text" />

编译时,它会被展开成两个东西:

  1. 数据绑定:value="text"
  2. 事件监听@input="text = $event.target.value"

工作流串联:

  1. 用户输入:触发 input 事件。
  2. 事件回调:执行 text = ...(修改响应式数据)。
  3. 响应式触发text 的 setter 触发 trigger。
  4. 组件更新:Render Effect 重新跑,生成新 VNode。
  5. DOM 更新:Input 的 value 属性被更新(虽然用户已经输进去了,但 Vue 会确保数据流的一致性)。

总结:全景图#

试着把你自己写的代码代入到这个流程里:

  1. 编译器.vue 变成 render 函数。
  2. 运行时创建一个 effect 来运行 render
  3. render 读取数据,你的 **Proxy **get 被触发,把 effect 存入 Set
  4. 数据变化,你的 **Proxy **set 被触发,调用 trigger
  5. trigger 通知 effect 重新运行。
  6. effect 重新运行 render 得到新 VNode。
  7. 渲染器 对比新旧 VNode,调用 DOM API 更新页面。

现在你已经明白了它们是怎么串联的。

  • 响应式:你已经通关了。
  • 编译时:这是一个纯文本处理工程,非常枯燥但强大。
  • 运行时 (Renderer/Diff):这是把虚拟变成现实的关键。