菜单

运行时系统

相关源文件

Svelte 运行时系统负责处理 Svelte 应用中的响应式、组件生命周期、DOM 操作和渲染。它弥合了编译器生成的优化 JavaScript 与实际 DOM 更新之间的差距。本页面解释了运行时系统的核心架构和机制,重点关注响应式、副作用和 DOM 操作如何协同工作。

有关将 Svelte 组件转换为使用此运行时生成的 JavaScript 的编译器信息,请参阅 编译器架构

概述

Svelte 运行时系统是一个小巧、高效的层,它提供了

  1. 响应式 - 状态管理和依赖项跟踪
  2. 副作用 - 状态变化时副作用的执行
  3. DOM 更新 - 高效的 DOM 操作
  4. 组件生命周期 - 组件的挂载、更新和卸载
  5. 水合 - 连接到服务器渲染的 HTML

此运行时采用精细的响应式系统,仅更新需要更改的 DOM 部分,避免了虚拟 DOM diffing 方法的开销。

来源

响应式系统

Svelte 的响应式系统围绕三个核心基元构建

  1. 源 (Sources) - 可读写的响应式值
  2. 派生值 (Derived Values) - 由响应式源计算出的值
  3. 副作用 (Effects) - 依赖项更改时运行的函数

源和状态

源是 Svelte 响应式系统的基础。它们代表可读写的可变值。当源更改时,所有依赖于它的副作用都会被调度执行。

source() 函数创建了一个简单的响应式值,而 mutable_source() 创建了一个具有特殊相等性检查(用于数组和对象)的响应式值。

来源

派生值

派生值是从一个或多个源计算得出的。它们是惰性求值的,并且仅当其依赖项发生更改且实际读取它们时才重新计算。

派生值会自动跟踪其依赖项。当派生值被读取时,它会在其计算过程中将自己注册为读取的任何源的依赖项。

来源

副作用

副作用是依赖项更改时运行的函数。有几种类型的副作用

  1. 用户副作用 ($effect) - 依赖项更改时运行,用于副作用
  2. 渲染副作用 - 用于 DOM 更新
  3. 块副作用 - 用于模板控制流(if/each 等)
  4. 根副作用 - 管理组件生命周期的顶级副作用

副作用通过记录执行过程中读取的源和派生值来自动跟踪其依赖项。

来源

副作用系统

副作用系统是一个分层的副作用树,它管理响应式更新何时以及如何发生。副作用被组织成一个树形结构

  1. 根副作用 - 顶级副作用(组件)
  2. 分支副作用 - 分支树的子副作用
  3. 块副作用 - 用于控制流(if/each 块)的副作用
  4. 渲染副作用 - 用于 DOM 更新的副作用
  5. 用户副作用 - 来自 $effect() 的自定义副作用

副作用树结构

每个副作用可以有子副作用,形成一个树。当一个副作用被调度运行时,它会按顺序处理其子项。

来源

副作用执行

当源发生变化时,所有依赖于它的副作用都会被标记为脏,并被调度执行。运行时系统利用微任务智能地批量处理这些更新,以提高效率。

副作用更新过程遵循以下步骤

  1. 标记相关的副作用为脏
  2. 调度副作用进行更新
  3. 排队根副作用
  4. 按树顺序处理副作用
  5. 检查每个副作用是否为脏
  6. 更新脏副作用
  7. 应用 DOM 更改

来源

组件生命周期

组件在生命周期中经历几个阶段

  1. 挂载 - 组件被创建并添加到 DOM
  2. 更新 - 组件状态更改触发更新
  3. 卸载 - 组件从 DOM 中移除

挂载

组件挂载时,mount() 函数会创建一个根副作用,该副作用执行组件函数。这会设置初始 DOM 结构和响应式。

来源

更新

当状态更改时,响应式系统会将副作用标记为脏并调度它们运行。这导致组件仅更新依赖于已更改状态的部分。

来源

卸载

组件卸载时,其根副作用会被销毁。这将递归地销毁所有子副作用,移除事件监听器,并可以选择运行退出过渡。

来源

DOM 管理

Svelte 直接操作 DOM,而不是使用虚拟 DOM。它结合使用了模板函数和基于副作用的更新。

模板

模板是根据 HTML 字符串创建 DOM 节点的函数。Svelte 将组件模板编译成高效的 JavaScript,用于创建和更新 DOM 元素。

来源

DOM 操作

DOM 操作是直接操作 DOM 的函数。这些包括

  • 创建元素
  • 设置属性
  • 添加事件监听器
  • 更新文本内容
  • 管理过渡

这些操作由响应状态变化的副作用触发。

来源

水合作用

水合是将客户端运行时连接到服务器渲染的 HTML 的过程。Svelte 使用特殊的标记注释来将客户端组件结构与服务器渲染的 DOM 匹配。

来源

控制流块

控制流块是处理条件渲染(if)、列表(each)、异步数据(await)等的特殊组件。每种块类型在运行时都有其自己的实现。

If 块

If 块根据值有条件地渲染内容。它们使用副作用来跟踪条件的更改并相应地更新 DOM。

来源

Each 块

Each 块渲染项目列表。它们能够以最少的 DOM 操作高效地处理添加、删除和重新排序。

来源

Await 块

Await 块处理异步数据,显示待处理、已完成或已拒绝的 Promise 的不同内容。

来源

关键的Blocks(Key Blocks)

关键 Blocks 在其值发生变化时强制重新渲染,这对于动画和过渡非常有用。

来源

代理系统

Svelte 使用 JavaScript 的 Proxy 来实现对象和数组的深度响应性。当一个对象被设置为响应式时,它会被包裹在一个 Proxy 中,该 Proxy 会拦截属性的访问和修改。

来源

错误处理

运行时包含强大的错误处理机制,用于捕获和报告在组件渲染或效果执行期间发生的错误。它使用错误边界将错误限制在组件内部。

来源

运行时工具

运行时提供了多种工具函数,支持核心的响应性和 DOM 操作。

  • flushSync() - 同步处理所有待处理的更新
  • tick() - 返回一个 Promise,该 Promise 在待处理的更新完成后解析
  • untrack() - 运行代码而不跟踪响应式依赖
  • snapshot() - 创建一个值的非响应式副本

这些工具可以帮助开发者控制运行时系统的时序和行为。

来源

结论

Svelte 运行时系统是一个复杂而精简的系统,可有效管理响应性、效果和 DOM 更新。通过使用细粒度的响应性和直接的 DOM 操作,它在保持开发者简单心智模型的同时实现了高性能。

该运行时围绕着源、派生值和效果的核心概念构建,所有这些都组织在一个分层树结构中,可以实现高效的更新。这种架构使 Svelte 能够以最小的开销提供响应式的用户体验。