Vue 3.6 本文将深入剖析 Vue 3.6 中引入的 Alien Signals——一次对响应式系统的彻底重构,以及它如何与 Vapor Mode 配合带来前所未有的性能提升。
前言:为什么需要重构响应式系统
Vue 3.x 系列已经在响应式系统上做了诸多优化,包括静态提升、Patch flags、编译时 hoisting 等。然而,随着前端应用规模的增长和对性能要求的提高,传统以 Proxy + 虚拟 DOM 为中心的追踪和更新方法暴露出了一些问题:
传统响应式系统的痛点
- 粗粒度追踪:组件级别的响应,导致不必要的重渲染
- 内存开销大:大量 VNode 对象的创建和销毁
- GC 压力:频繁的对象创建导致垃圾回收压力增大
- 计算冗余:computed 即使未被访问也可能被计算
- 依赖追踪开销:依赖收集和清理机制不够高效
官方 CHANGELOG 说明
Alien Signals 的目标
| 目标 | 说明 |
|---|---|
| ✅ 减少无关更新 | 只在真正依赖的数据变更时触发响应 |
| ✅ 提高计算效率 | computed 的惰性计算更加彻底 |
| ✅ 降低内存使用 | 减轻垃圾回收(GC)压力 |
| ✅ 保持 API 兼容 | 开发者迁移成本低 |
什么是 Signals(信号)
在深入 Alien Signals 之前,我们需要理解什么是"信号"。
信号的定义
Signal 是现代响应式框架的核心概念。
信号的核心组件
Vue 现有 API 与信号的对应关系
| Vue 现有 API | 信号概念 | 说明 |
|---|---|---|
ref() |
Signal | 保存响应式值 |
reactive() |
Signal (Object) | 保存响应式对象 |
computed() |
Computed | 派生状态 |
watch() / watchEffect() |
Effect | 监听变化并执行副作用 |
Alien Signals 核心机制
Alien Signals 是 Vue 3.6 对 @vue/reactivity 包的完全重构。它的名字来源于 stackblitz-labs 开源的项目:
核心设计理念
Fine-grained Tracking
不再是组件级别,而是精确到每个信号。每个 ref 或 signal 都独立追踪其依赖者,确保更新只影响真正需要更新的部分。
javascript
const count = signal(0);
const doubled = computed(() => count() * 2);
// 只有 doubled 会在 count 变化时重新计算
Lazy Evaluation
computed 只在被访问时才计算,且缓存结果。如果没有被读取,即使依赖变化也不会触发计算。
javascript
const expensive = computed(() => {
// 只有在 expensive.value 被访问时才执行
return heavyCalculation();
});
Smart Propagation
只通知真正需要更新的下游依赖。通过版本标记和脏检查,避免不必要的更新传播。
Efficient Cleanup
依赖关系的建立和清除更加轻量。使用双向链表替代传统的 Set/Map,减少内存分配和 GC 压力。
Push-Pull-Push 混合模型详解
Alien Signals 最核心的创新是采用了 Push-Pull-Push 混合更新传播模型。这与传统的 Push-only 或 Pull-only 模型有本质区别。
三阶段更新流程
完整流程图:
详细流程说明
推送脏标记
javascript
// 当一个 signal 的值更新时
const count = signal(1);
// 内部发生:
// 1. 更新 signal 的值
// 2. 遍历所有订阅者(computed/effect)
// 3. 将它们标记为 "dirty"(脏)
// 4. 但不立即重新计算!
count.value = 2; // 只标记,不计算
拉取计算
javascript
const doubleCount = computed(() => count.value * 2);
// 当 doubleCount 被访问时:
console.log(doubleCount.value);
// 内部发生:
// 1. 检查自己是否被标记为 "dirty"
// 2. 如果是,检查依赖的 signal 是否真的变化了
// 3. 只有真的变化了,才重新计算
// 4. 缓存新结果
推送更新
javascript
// computed 重新计算后,如果结果变化了
// 会 push 通知依赖它的 effect
effect(() => {
console.log(doubleCount.value); // 被通知更新
});
为什么这种模型更高效?
查看对比示例
javascript
数据结构:双向链表与版本标记

双向链表结构
Alien Signals 使用双向链表来管理依赖关系,这比传统的 Set/Map 方式更高效:
双向链表依赖追踪结构图:
版本标记机制
typescript
版本标记的作用:
javascript
// 快速判断是否需要更新
function shouldRecompute(computed) {
for (let link of computed.sources) {
if (link.source.version !== link.lastSeenVersion) {
return true; // 依赖的 signal 版本变了,需要重算
}
}
return false; // 所有依赖都没变,跳过计算
}
Vue 3.6 源码深度解析
让我们深入 Vue 3.6 的源码,看看 Alien Signals 是如何实现的。
源码仓库结构
关键文件说明
| 文件 | 说明 | GitHub 链接 |
|---|---|---|
system.ts |
核心信号系统,从 alien-signals 移植 | 查看源码 |
dep.ts |
依赖追踪实现 | 查看源码 |
effect.ts |
Effect 实现 | 查看源码 |
computed.ts |
Computed 实现 | 查看源码 |
ref.ts |
Ref 实现 | 查看源码 |
核心接口定义(system.ts)

查看 ReactiveNode 和 Link 接口定义
源码位置:packages/reactivity/src/system.ts
typescript
ReactiveFlags 状态标记
查看状态标记枚举
源码位置:packages/reactivity/src/system.ts#L30-L38
typescript
export const enum ReactiveFlags {
None = 0,
Mutable = 1 << 0, // 可变(computed)
Watching = 1 << 1, // 正在监听(effect)
RecursedCheck = 1 << 2, // 递归检查中
Recursed = 1 << 3, // 已递归
Dirty = 1 << 4, // 脏值,需要重新计算
Pending = 1 << 5, // 等待中
}
标记位说明:
Dirty:表示值已过期,需要重新计算Pending:表示可能需要更新,但还未确认Mutable:表示是 computed(可变的派生值)Watching:表示是 effect(正在监听变化)
link 函数 - 建立依赖关系

查看 link 函数实现
源码位置:packages/reactivity/src/system.ts#L67-L111
typescript
关键优化点:
- 快速路径检查:避免重复创建已存在的链接
- 版本号更新:通过
globalVersion追踪依赖变化 - 双向链表操作:O(1) 时间复杂度的插入和删除
propagate 函数 - 传播更新

查看 propagate 函数实现
源码位置:packages/reactivity/src/system.ts#L151-L219
typescript
传播策略:
- 使用栈模拟递归,避免调用栈溢出
- 只标记
Pending,不立即计算 - Effect 被加入
notifyBuffer,批量处理
checkDirty 函数 - 脏检查

查看 checkDirty 函数实现
源码位置:packages/reactivity/src/system.ts#L261-L333
typescript
脏检查优化:
- 惰性检查:只有在访问时才检查
- 递归检查:沿着依赖链向上追溯
- 提前终止:一旦确定不脏,立即返回
Effect 类实现

查看 ReactiveEffect 类
源码位置:packages/reactivity/src/effect.ts#L58-L166
typescript
Effect 的关键特性:
- 实现了
ReactiveNode接口 dirtygetter 实现了惰性脏检查run()方法处理依赖追踪和清理
API 使用示例
基础用法
javascript
effectScope 管理多个 effects
javascript
与现有 Vue API 共存
vue
Vapor Mode:编译时优化的完美搭档
什么是 Vapor Mode?
Vapor Mode 是 Vue 3.6 引入的全新编译模式,它与 Alien Signals 配合,完全绕过虚拟 DOM,直接生成操作真实 DOM 的代码。
渲染模式对比
Template → VNode → Diff → Patch → Real DOM
流程:
- 模板编译为渲染函数
- 渲染函数生成虚拟 DOM 树
- 新旧 VNode 进行 Diff 比较
- 生成 Patch 操作
- 应用到真实 DOM
Template → 直接 DOM 操作代码 → Real DOM
流程:
- 模板编译为直接操作 DOM 的代码
- 信号变化直接触发对应 DOM 更新
- 无 VNode 创建、无 Diff、无 Patch
如何启用 Vapor Mode
vue
编译输出对比
javascript
javascript
Alien Signals + Vapor Mode 的协同效应
双重优化的协同效应
| 层面 | Alien Signals | Vapor Mode |
|---|---|---|
| 作用层 | 运行时响应式 | 编译时优化 |
| 核心价值 | 细粒度追踪 | 绕过虚拟 DOM |
| 组合效果 | Signal 变化 → 直接精确更新对应 DOM 节点 |
最终效果:
- Signal 变化
- ↓ 精确定位受影响的 DOM 节点
- ↓ 直接更新该 DOM 节点(跳过 Diff/Patch)
性能对比与基准测试
Bundle 大小对比
| 模式 | Hello World 大小 | 减少比例 |
|---|---|---|
| VDOM 模式 | ~22.8 KB | - |
| Vapor 模式 | ~7.9 KB | -65% |
运行时性能对比
| 场景 | Vue 3.5 | Vue 3.6 (Alien Signals) | 提升 |
|---|---|---|---|
| 10 万组件挂载 | ~300ms | ~100ms | 3x |
| 响应式对象内存 | 100% | ~60% | -40% |
| computed 重计算 | 100% | ~20% | 5x |
| GC 频率 | 高 | 低 | 显著降低 |
实际性能测试对比
我们使用相同的测试用例,分别在 Vue 3.5.x 和 Vue 3.6.x 中运行,以下是实测结果:


测试结果分析:
| 测试项 | Vue 3.5.x | Vue 3.6.x | 提升幅度 |
|---|---|---|---|
| 创建 refs | 35.90 ms | 33.80 ms | 6% ↑ |
| 创建 computed | 16.10 ms | 14.50 ms | 10% ↑ |
| 批量更新 refs | 12.60 ms | 11.40 ms | 10% ↑ |
| 创建 effects | 16.70 ms | 11.10 ms | 33% ↑ |
| 深度依赖链 | 4.47 s | 2.94 s | 34% ↑ 🔥 |
| 批量访问 computed | 30.70 ms | 23.00 ms | 25% ↑ |
| 钻石依赖 | 5.71 s | 5.19 s | 9% ↑ |
| 内存占用 | 30.4 MB | 19.0 MB | 37% ↓ 🔥 |
Chrome DevTools Performance 面板对比

Vue 3.6 执行统计:
- 总耗时:4,035 ms
- 脚本执行:2,937 ms
- 主线程耗时:2,898.6 ms

Vue 3.5.x 执行统计:
- 总耗时:5,000 ms
- 脚本执行:3,666 ms
- 主线程耗时:3,625.0 ms
Chrome DevTools Memory 面板对比

Vue 3.6 内存分析:
- 堆快照大小:45.0 MB
- Function 对象:×291,964 个
- 无独立 Dep 类实例 ✅

Vue 3.5.x 内存分析:
- 堆快照大小:60.4 MB
- Dep 类实例:×300,011 个(14,401 kB)
- Function 对象:×407,025 个
JS Framework Benchmark 对比
官方声明:
"Vapor Mode has demonstrated the same level of performance with Solid and Svelte 5 in 3rd party benchmarks."
具体场景测试
大量 computed 依赖测试
javascript
迁移指南与注意事项
Vapor Mode 当前限制
Vapor Mode 当前不支持的特性
| 特性 | 状态 | 说明 |
|---|---|---|
| Options API | ❌ 不支持 | 必须使用 <script setup> |
| SSR Hydration | ❌ 不支持 | 等待后续版本 |
<Transition> / <TransitionGroup> |
❌ 不支持 | 过渡动画 |
<KeepAlive> |
❌ 不支持 | 组件缓存 |
<Suspense> |
⚠️ 部分支持 | 可在 VDOM Suspense 中使用 Vapor 组件 |
<Teleport> |
⚠️ 部分支持 | 部分场景可用 |
getCurrentInstance() |
❌ 返回 null | 在 Vapor 组件中不可用 |
app.config.globalProperties |
❌ 不支持 | 全局属性 |
@vue:xxx 生命周期事件 |
❌ 不支持 | 元素级生命周期 |
渐进式迁移策略
javascript
vue
vue
迁移建议
测试覆盖建议
javascript
总结
Vue 3.6 响应式系统的三大核心升级
技术架构总览
适用场景
| 场景 | 推荐程度 | 说明 |
|---|---|---|
| 新项目 | ⭐⭐⭐⭐⭐ | 可以从一开始就使用 Vapor Mode |
| 大型组件树 | ⭐⭐⭐⭐⭐ | 性能提升最明显 |
| 实时数据应用 | ⭐⭐⭐⭐⭐ | 高频更新场景受益最大 |
| 移动端应用 | ⭐⭐⭐⭐ | 内存和性能敏感 |
| 现有大型项目 | ⭐⭐⭐ | 渐进式迁移,先迁移热点组件 |
| 依赖 SSR 的项目 | ⭐⭐ | 等待 Vapor Mode 支持 SSR |
展望
Vue 3.6 的 Alien Signals + Vapor Mode 代表了 Vue 框架的一次重大进化。它不仅仅是性能优化,更是响应式编程范式的一次升级。随着 Vapor Mode 功能的完善和生态的成熟,Vue 将在性能上与 Solid、Svelte 等信号优先框架站在同一起跑线上,同时保持 Vue 一贯的优秀开发体验。
参考资料
源码直达链接
| 文件 | 说明 |
|---|---|
| system.ts | 核心信号系统 |
| dep.ts | 依赖追踪 |
| effect.ts | Effect 实现 |
| computed.ts | Computed 实现 |
| CHANGELOG.md | 更新日志 |

