当前位置: 首页 > news >正文

Vue 3 的运行机制

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 settertrigger() → scheduler → effect()│▼patch → DOM diff → beforeUpdate → updated

一句话总结

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

http://www.dtcms.com/a/332817.html

相关文章:

  • 前端开发神器之 VS Code AI 辅助插件 Amazon Q
  • expand.exe命令为什么能显示CD.iso的版本信息?
  • vue3 wangeditor5 编辑器,使用方法
  • 非极大值抑制(NMS)详解:目标检测中的“去重神器”
  • 基于 Vue2+Quill 的富文本编辑器全方案:功能实现与样式优化
  • 列式存储与行式存储:核心区别、优缺点及代表数据库
  • Flink Stream API 源码走读 - map 和 flatMap
  • ETH持续上涨推动DEX热潮,交易活跃度飙升的XBIT表现强势出圈
  • MySQL 全面指南:从入门到精通——深入解析安装、配置、操作与优化
  • 从阻塞到异步:Java IO 模型进化史 ——BIO、NIO、AIO 深度解析
  • Cherryusb UAC例程对接STM32 SAI播放音乐和录音(下)=>USB+SAI+TX+RX+DMA控制WM8978播放和录音实验
  • 【嵌入式FreeRTOS#补充1】临界区
  • K-means 聚类算法学习笔记
  • 解锁PostgreSQL专家认证增强驱动引擎
  • 打靶日常-sql注入(手工+sqlmap)
  • 136-基于Spark的酒店数据分析系统
  • Python Sqlalchemy数据库连接
  • 紫金桥RealSCADA:国产工业大脑,智造安全基石
  • 【已解决】在Spring Boot工程中,若未识别到resources/db文件夹下的SQL文件
  • JavaScript 防抖(Debounce)与节流(Throttle)
  • 易道博识康铁钢:大小模型深度融合是现阶段OCR的最佳解决方案
  • 【Trans2025】计算机视觉|UMFormer:即插即用!让遥感图像分割更精准!
  • Notepad++插件开发实战指南
  • Radar Forward-Looking Imaging Based on Chirp Beam Scanning论文阅读
  • 《WINDOWS 环境下32位汇编语言程序设计》第1章 背景知识
  • 【Linux】探索Linux虚拟地址空间及其管理机制
  • C# HangFire的使用
  • 概率论基础教程第2章概率论公理(习题和解答)
  • 在 Linux 服务器搭建Coturn即ICE/TURN/STUN实现P2P(点对点)直连
  • HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新