反应性系统是 Svelte 性能和开发者体验的核心。它能够在使用虚拟 DOM 差异化方法的情况下,在组件状态发生变化时自动更新 DOM。本页将从开发者使用和内部实现的角度解释 Svelte 的反应性模型的工作原理。
有关组件生命周期信息,请参阅组件生命周期。
Svelte 的反应性系统使用细粒度的依赖项跟踪,可以在状态更新时高效地仅更新需要更改的 DOM 部分。在 Svelte 5 中,这主要通过“runes”来暴露——以 $ 开头的特殊函数,它们充当反应性原语。
来源:packages/svelte/src/internal/client/runtime.js1-150 packages/svelte/src/internal/client/reactivity/effects.js1-80 packages/svelte/src/internal/client/reactivity/sources.js1-80
Svelte 的反应性系统构建在四个主要原语之上
| 原语 | 目的 | 内部表示 |
|---|---|---|
$state() | 创建反应性状态变量 | 来源 |
$derived() | 从反应性依赖项计算值 | 派生 |
$effect() | 在依赖项更改时运行副作用 | 效果 |
$props() | 提供反应性组件属性 | 来源 |
这些原语编译为一个细粒度的反应性系统,能够高效地跟踪依赖项和进行更新。
来源:packages/svelte/types/index.d.ts350-465
在内部,Svelte 的反应性是构建在三种核心的 Signal 类型之上的
$state() 或其他方式创建的原始反应性值来源:packages/svelte/src/internal/client/reactivity/sources.js30-100 packages/svelte/src/internal/client/reactivity/deriveds.js1-80 packages/svelte/src/internal/client/reactivity/effects.js60-150
当反应性值在 effect 或派生值计算执行期间被读取时,反应性系统会自动建立依赖关系。
涉及的关键机制
active_reaction 和 active_effect 变量会跟踪当前正在执行的反应性计算get() 函数在返回值的同事注册依赖项reactions 数组,包含所有依赖的计算来源:packages/svelte/src/internal/client/runtime.js70-120 packages/svelte/src/internal/client/runtime.js870-950
Signals 带有状态标志,用于确定何时需要更新它们
| 状态 | 描述 |
|---|---|
CLEAN (干净) | 最新,无需更新 |
MAYBE_DIRTY (可能脏) | 依赖项已更改,需要评估 |
DIRTY (脏) | 肯定需要重新评估 |
当源值更改时,其依赖项会被标记为脏,并在依赖项图中传播。
来源:packages/svelte/src/internal/client/runtime.js160-230 packages/svelte/src/internal/client/constants.js10-25
Effects 被组织成一个树状结构,以实现高效的更新和清理。
来源:packages/svelte/src/internal/client/reactivity/effects.js65-150 packages/svelte/src/internal/client/reactivity/effects.js380-460
当一个反应性源发生变化时
来源:packages/svelte/src/internal/client/runtime.js740-765 packages/svelte/src/internal/client/reactivity/sources.js130-220
flushSync 进行批处理flushSync 函数允许强制所有待处理的更新同步完成
来源:packages/svelte/src/internal/client/runtime.js835-855
有时您可能希望读取一个反应性值而不创建依赖项。 untrack 函数允许这样做
来源:packages/svelte/src/internal/client/runtime.js1010-1035
当使用 $state() 处理对象或数组时,Svelte 会自动代理它们,使所有嵌套属性都具有反应性
这允许像 user.settings.theme = 'light' 这样的直观嵌套更新来正确地触发反应性。
来源:packages/svelte/src/internal/client/proxy.js20-130 packages/svelte/src/internal/client/runtime.js1070-1140
Svelte 5 引入了 runes 作为表达反应性的新方法,取代了先前的反应性声明和 store 订阅。
| 旧版功能 | Runes 等效功能 | 描述 |
|---|---|---|
let count = 0; + 反应性 | let count = $state(0); | 反应性状态变量 |
$: doubled = count * 2; | let doubled = $derived(count * 2); | 派生值 |
$: { /* effect */ } | $effect(() => { /* effect */ }); | 副作用 |
export let prop; | let { prop } = $props(); | 组件属性 |
$store | 直接访问 store 值 | Store 订阅 |
runes 系统提供了更明确、更一致的反应性语义。
来源: packages/svelte/src/compiler/phases/2-analyze/index.js400-460 packages/svelte/src/compiler/phases/scope.js600-650
Svelte 的响应式系统包含强大的错误处理功能
BOUNDARY_EFFECT 的 Effect(副作用)充当错误边界这使得构建能够从错误中恢复的弹性响应式应用程序成为可能。
来源: packages/svelte/src/internal/client/runtime.js230-360
Svelte 的响应式系统以高性能为设计目标
来源: packages/svelte/src/internal/client/runtime.js560-630 packages/svelte/src/internal/client/reactivity/effects.js80-150
Svelte 的响应式系统提供了一种强大而直观的方式来构建动态用户界面。通过自动跟踪依赖关系并仅高效地更新需要更改的部分,它在保持对开发者友好的 API 的同时,提供了出色的性能。
理解这些内部机制可以帮助您编写更高效的 Svelte 组件,并在出现响应式问题时进行有效调试。