菜单

渲染系统

相关源文件

Vue.js 的渲染系统负责高效地将组件模板和响应式状态转换为 DOM 操作。它处于 Vue 响应式模型的核心,决定着应用程序状态的变化如何以及何时反映在 UI 中。本文档重点介绍核心渲染系统的架构和工作流程。

有关渲染系统特定方面的更多详细信息,请参阅有关 虚拟 DOM服务端渲染过渡 的页面。

渲染系统架构

Vue.js 渲染系统采用基于虚拟 DOM 的方法,通过模块化架构实现,将核心渲染逻辑与平台特定的 DOM 操作分离。

来源

渲染系统被设计为与平台无关,核心逻辑在 runtime-core 中定义,并通过一组选项提供平台特定的实现。主要组件包括:

  1. 渲染器工厂createRenderer 函数创建为特定平台(浏览器 DOM、服务器端渲染等)配置的渲染器实例。

  2. VNode 处理器patch 函数根据 VNode 的类型递归处理虚拟 DOM 节点。

  3. 元素处理器processElementprocessComponent 等函数处理不同的 VNode 类型。

  4. DOM 操作:用于挂载(mountElementmountComponent)和更新(patchElementupdateComponent) DOM 元素的函数。

  5. 响应式集成setupRenderEffect 创建将状态更改连接到渲染器更新的响应式效果。

渲染过程工作流

渲染过程涉及从组件创建到 DOM 更新的流程,响应式集成实现了自动 UI 更新。

来源

渲染过程遵循以下步骤:

  1. 组件创建:当组件首次创建时,createComponentInstance 会初始化一个新组件实例。

  2. 组件设置setupComponent 处理 props、slots 并执行 setup 函数以建立响应式状态。

  3. 渲染效果设置setupRenderEffect 创建一个响应式效果,该效果会:

    • 调用组件的渲染函数以创建 VNode 树
    • 通过 patch 函数处理此树以更新 DOM
    • 每当响应式依赖项更改时重新运行
  4. 初始渲染:初始渲染会创建完整的 DOM 结构。

  5. 更新周期:当响应式状态更改时,渲染效果会被触发,生成一个新的 VNode 树,并高效地与前一个 VNode 树进行 patch。

组件渲染生命周期

组件在渲染过程中会经历特定的生命周期阶段,并在关键节点提供钩子。

来源

组件渲染生命周期包括:

  1. 创建阶段:

    • 使用 createComponentInstance 创建组件实例
    • 使用 setupComponent 设置组件(props、slots、state)
    • 使用 setupRenderEffect 创建渲染效果
  2. 挂载阶段:

    • 调用 beforeMount 生命周期钩子
    • 使用 renderComponentRoot 执行渲染函数
    • 使用 patch 处理 VNode 树
    • 调用 mounted 生命周期钩子
  3. 更新阶段:

    • 当依赖项更改时,触发渲染效果
    • 调用 beforeUpdate 生命周期钩子
    • 重新执行渲染函数以获取新的 VNode 树
    • Patch 差异到 DOM
    • 调用 updated 生命周期钩子
  4. 卸载阶段:

    • 调用 beforeUnmount 生命周期钩子
    • 从 DOM 中移除组件
    • 调用 unmounted 生命周期钩子

VNode Patching 过程

patch 函数是 Vue diff 和更新机制的核心,它决定了如何高效地更新 DOM。

来源

Patching 过程的逻辑因节点类型而异

  1. Patch 入口点:调用 patch 函数,传入前一个 VNode(n1)、新 VNode(n2)和容器。

  2. 类型检查:

    • 如果节点类型不同,则卸载旧节点并挂载新节点。
    • 如果节点类型相同,则根据特定类型(元素、组件、片段等)进行处理。
  3. 元素 Patching:

    • 首次:mountElement 创建新的 DOM 元素。
    • 更新:patchElement 更新现有的 DOM 元素,处理:
      • Props 更新
      • 子节点更新
  4. 组件 Patching:

    • 首次:mountComponent 创建并设置组件。
    • 更新:updateComponent 确定组件是否需要更新并触发重新渲染。
  5. 优化:该过程使用多种优化技术。

    • PatchFlags 以跳过不必要的操作
    • Block Tree 以跟踪动态节点
    • Dynamic Children 以仅 patch 可更改的节点

渲染器创建

Vue 的渲染系统设计为平台无关,通过渲染器选项提供平台特定的详细信息。

来源

渲染器创建的关键方面

  1. 渲染器工厂createRenderer 函数接受平台特定的实现细节:

    • 节点插入/移除
    • 属性/特性 patching
    • 元素/文本创建
    • 元素/文本操作
  2. 基础渲染器创建baseCreateRenderer 函数:

    • 创建核心渲染函数(patchrender 等)
    • 创建包含以下内容的渲染器接口:
      • render:用于挂载到容器
      • createApp:用于创建应用程序实例的工厂
  3. 平台适配 (Platform Adaptation):

    • 浏览器 DOM 实现由 runtime-dom 提供
    • 服务器端渲染由 server-renderer 提供
    • 自定义渲染器可以实现自己的 DOM 操作
  4. 渲染器 API:生成的渲染器公开:

    • render:将 VNode 渲染到容器的函数
    • createApp:用于创建绑定到此渲染器的应用程序实例的工厂

组件-渲染器集成

组件通过特定的接口和生命周期与渲染系统集成。

来源

组件-渲染器集成包括:

  1. 组件实例创建createComponentInstance 初始化新组件,包含:

    • 组件类型和 props
    • 父组件上下文
    • 响应式效果作用域
  2. 组件设置setupComponent 准备组件:

    • 初始化 props 和 slots
    • 使用适当的上下文调用 setup 函数
    • 处理 setup 结果(响应式状态、渲染函数)
  3. 渲染效果设置setupRenderEffect 创建响应式效果:

    • 创建渲染组件的 effect 函数
    • 将其分配给 instance.update
    • 处理组件生命周期钩子
  4. 渲染过程:

    • 组件的渲染函数生成 VNode 树
    • VNode 树由 patching 算法处理
    • DOM 相应地更新
  5. 更新:

    • 当响应式依赖项更改时,触发 effect
    • 组件重新渲染,生成新的 VNode 树
    • Patching 算法仅更新已更改的部分

优化技术

Vue 的渲染系统包含多种优化技术以提高性能。

来源

Vue 渲染系统中的关键优化技术

  1. PatchFlags:指示节点哪些部分需要更新的数字标志。

    • CLASS (1):仅 class 需要更新。
    • STYLE (2):仅 style 需要更新。
    • PROPS (4):仅部分 props 需要更新。
    • TEXT (8):仅 text content 需要更新。
    • FULL_PROPS (32):所有 props 都可能需要更新。
  2. Block Tree:跟踪动态节点的结构。

    • openBlock():开始跟踪动态节点。
    • createBlock():创建一个 block 根节点,该节点跟踪动态子节点。
    • 仅跟踪可能更改的节点,减少 diff 工作量。
  3. Dynamic Children:允许直接 patch 动态节点。

    • 父节点在 vnode.dynamicChildren 中跟踪动态子节点。
    • Patching 算法可以跳过树的稳定部分。
    • patchBlockChildren() 直接 patch 动态节点,无需遍历稳定节点。
  4. 静态提升:在编译期间:

    • 静态内容会被提升出渲染函数。
    • 仅创建一次并复用。
    • 静态节点无需重新创建或 diff。

这些优化通过以下方式显著提高了渲染性能:

  • 减少不必要的 DOM 操作
  • 最小化 VNode 树遍历
  • 将 diff 操作集中在实际可更改的节点上

总结

Vue 的渲染系统是一个复杂的管道,它将组件模板和响应式状态转换为高效的 DOM 操作。虚拟 DOM 抽象、响应式系统和各种优化技术的结合,使得 Vue 既能提供开发者友好的抽象,又能实现高性能的 UI 更新。

核心架构将渲染逻辑(在 runtime-core 中实现)与平台特定操作(由 runtime-dom 和其他实现提供)分离,使系统具有灵活性和可扩展性。这种清晰的分离也支持服务器端渲染和自定义渲染器等高级功能。

Patching 算法智能地确定所需的最小 DOM 操作集,而像 patch flags 和 block tree 这样的优化技术通过跳过不必要的工作进一步提高了性能。这些元素共同构成了一个统一的系统,能够处理 UI 渲染的复杂性,同时保持出色的性能。

来源