前段时间,社区掀起了一股 alien-signals 的热潮,其惊人的性能表现让许多开发者印象深刻。作为一名前端开发者,我深入研究了它的源码,探索其性能优势的秘密。
本文将开启一个全新的系列,深入剖析 alien-signals 的使用方法、实现原理和性能优化等内容。让我们一起揭开 alien-signals 的神秘面纱。
为什么要关注 alien-signals?
在深入技术细节之前,让我们先看看 alien-signals 在性能基准测试中的表现。根据 js-reactivity-benchmark 的数据,alien-signals 在各项性能指标上都遥遥领先:

各响应式框架性能对比,alien-signals 在各项指标上遥遥领先
这样的性能表现,加上 Vue 3.6 即将采用 alien-signals 重构响应式系统的消息,使得它成为了前端社区的焦点。
Signals 概念
如果对 Signals 概念还不熟悉,推荐先阅读我之前的文章:理解 Signal 是如何工作的,其中详细介绍了 Signals 的基本原理和工作机制。
简单来说,Signals 是一种响应式编程模式,它允许我们创建可观察的值和计算属性,当依赖发生变化时自动更新。
响应式库
先简单了解一下什么是响应式框架:
Reactivity is the future of JS frameworks! Reactivity allows you to write lazy variables that are efficiently cached and updated, making it easier to write clean and fast code. ------ 引自 Super Charging Fine-Grained Reactive Performance · milomg.dev
响应式是 JS 框架的未来!响应性允许您编写有效缓存和更新的惰性变量,从而更轻松地编写干净、快速的代码。
而且响应式库是 Solid、Qwik、Vue 和 Svelte 等现代 Web 组件框架的核心。在某些情况下,您可以将细粒度的响应式状态管理添加到其他库,例如 Lit 和 React。
关于响应式算法的深入探讨,推荐阅读 深入探索细粒度响应式框架的性能优化 ,其中详细对比了 MobX、Preact Signals 和 Reactively 三种主流算法的实现原理。
响应式框架的目标
响应式库的目标是在响应式函数的源发生变化时运行响应式函数。
此外,响应式库还应该是:
- 高效:永远不要过度执行响应式元素(如果它们的源没有改变,请不要重新运行)
- 无故障:永远不要允许用户代码看到只有一些响应式元素更新的中间状态(当你运行响应式元素时,每个源都应该更新)
响应式框架的分类
在深入 alien-signals 之前,我们需要了解响应式框架的基本分类。
-
按执行时机分类
响应式框架根据执行时机可以分为两大类:
-
Lazy(惰性) :只在结果被访问时才进行计算,延迟执行,按需计算的思想能有效减少冗余计算。
- 代表:Solid.js、Preact Signals、Vue、alien-signals
-
Eager(即时性) :数据变化时立即计算,实时响应,但可能导致频繁计算的性能问题。
- 代表:MobX
💡 关于 Solid 的 Signals 的原理,可以参考我的另一篇文章:Solid 之旅 ------ Signal 响应式原理。
-
-
按更新传播算法分类
根据 维基百科对响应式编程的定义,更新传播算法可以分为三种模式:
-
Push-based(推送模型)
- 相当于 Eager 模型
- 依赖项变化时立即推送完整的变化信息给订阅者
- 类似于服务端向客户端的 SSE 推送机制
-
Pull-based(拉取模型)
- 相当于 Lazy 模型
- 只在需要时(如读取 computed 值)才拉取依赖项的变化
- 类似于客户端向服务端的轮询机制
-
Push-pull hybrid(推拉混合模型)
- 结合了推送和拉取的优点
- Push 阶段:依赖项变化时推送脏标记,通知订阅者需要更新
- Pull 阶段:订阅者在需要时拉取具体的变化值
-
Vue Signals 进化论
要理解 alien-signals 的由来,我们需要回顾 Vue 响应式系统的演进历程。这部分内容深受 Vue Signals 进化论系列文章 的启发。
-
Vue 3.5:借鉴 Preact Signals
Vue 3.5 的响应式重构直接受到了 Preact Signals 的启发,主要借鉴了两个核心设计:
- 版本计数(Version Counting) :用于快速判断依赖是否发生变化
- 双向链表结构:高效管理依赖关系
这些设计思想将在后续的系列文章中详细解析。
-
Vue 3.6:拥抱 alien-signals
alien-signals 在继承 Preact Signals 优秀设计的基础上,进行了大量性能优化:
- 延续双向链表设计:保持了高效的依赖管理
- 简化节点属性:减少内存占用
- 贴近 Vue 的命名规范:更好的生态融合
- 极致的性能优化:包括模拟递归调用栈、内存对齐、位运算等技巧
虽然这些优化在一定程度上牺牲了代码的可读性,但换来的是卓越的运行时性能。
使用
基础 API 使用
alien-signals 提供了简洁直观的 API:
typescript
import { signal, computed, effect } from 'alien-signals';
// 创建响应式信号
const count = signal(1);
// 创建计算属性
const doubleCount = computed(() => count() * 2);
// 创建副作用
effect(() => {
console.log(`Count is: ${count()}`);
});
// 输出: Count is: 1
// 读取计算属性
console.log(doubleCount());
// 输出: 2
// 更新信号值
count(2);
// 触发 effect,输出: Count is: 2
// 计算属性自动更新
console.log(doubleCount());
// 输出: 4
Effect Scope
alien-signals 还提供了作用域管理功能,方便批量管理副作用:
typescript
import { signal, effect, effectScope } from 'alien-signals';
const count = signal(1);
// 创建作用域
const stopScope = effectScope(() => {
effect(() => {
console.log(`Count in scope: ${count()}`);
});
// 输出: Count in scope: 1
});
count(2);
// 输出: Count in scope: 2
// 停止作用域内的所有副作用
stopScope();
count(3);
// 不再有输出,因为 effect 已被清理
架构设计
了解了基本使用后,让我们简单地了解 alien-signals 的架构设计。alien-signals 采用了优雅的双层架构设计:
1. System 层(响应式系统核心)
提供了 createReactiveSystem()
工厂函数,用于构建自定义响应式 API:
typescript
import { createReactiveSystem } from './system.js';
const {
link, // 建立依赖关系
unlink, // 解除依赖关系
propagate, // 传播更新
checkDirty, // 检查脏状态
endTracking, // 结束依赖追踪
startTracking, // 开始依赖追踪
shallowPropagate, // 浅层传播
} = createReactiveSystem({
update, // 更新回调
notify, // 通知回调
unwatched, // 未观察状态回调
});
2. Surface API 层(面向用户的 API)
基于 System 层构建的标准响应式 API,包括 signal、computed、effect 等。您可以参考 alien-signals 的实现 来构建自己的响应式 API。
总结
本文介绍了 alien-signals 的背景、核心概念以及基本使用方法。我们了解到:
- alien-signals 是当前性能最优秀的响应式框架之一
- 它继承了 Preact Signals 的优秀设计,并进行了极致的性能优化
- Vue 3.6 即将采用它来重构响应式系统,足见其价值
- 其双层架构设计既保证了性能,又提供了良好的扩展性
在下一篇文章中,我将深入 alien-signals 的 system 层,详细剖析其响应式机制的实现原理,包括依赖追踪、更新传播、脏检查等核心算法。敬请期待!