本文翻译自 Super Charging Fine-Grained Reactive Performance

作者:Milo (@milomg)

译者:JinSo

译注:本文作为理解现代响应式框架的基础文章,详细介绍了三种主要的细粒度响应式算法(MobX、Preact Signals、Reactively)的核心原理和性能特点。这些算法原理为后续深入理解 alien-signals 的创新设计和极致性能优化提供了重要的理论基础。

什么是响应式库?

响应式是 JS 框架的未来!响应式允许你编写惰性变量,这些变量能够高效地缓存和更新,让你更容易编写简洁快速的代码。

我一直在开发一个新的细粒度响应式库 Reactively,这个项目的灵感来源于我在 SolidJS 团队的工作经历。Reactively 目前是同类响应式库中最快的。你现在就可以单独使用 Reactively,未来 Reactively 的设计思想也将帮助 SolidJS 变得更快。

让我们一起探索细粒度响应式的不同算法实现,我会向你介绍我的新响应式库,并通过基准测试来比较三个库的性能表现。

介绍 Reactively

细粒度响应式库最近越来越受欢迎。新兴的库包括 Preact Signalsµsignal 和现在的 Reactively,以及一些历史更悠久的库如 SolidS.jsCellX。使用这些库,程序员可以让单个变量和函数变成响应式的。响应式函数会自动运行,并在其依赖源发生变化时重新运行。

译注:Vue 3.5 和即将到来的 Vue 3.6(alien-signals)也采用了类似的细粒度响应式设计。

使用像 Reactively 这样的库,你可以轻松地为 TypeScript/JavaScript 程序添加惰性变量、缓存和增量重计算功能。Reactively 非常小巧(< 1kb)且 API 简单。希望 Reactively 能让你轻松探索响应式编程的优势。

下面是使用 Reactively 实现惰性变量的例子:

import { reactive } from "@reactively/core";
const nthUser = reactive(10);
// fetch 调用会延迟到需要时才执行
const lazyData = reactive(() =>
  fetch(`https://data.mysite.io/users?n=${nthUser.value}`)
); 
if (needUsers) {
  useBuffer(await lazyData.value);
}

响应式库通过维护响应式元素之间的依赖关系图来工作。现代库会自动发现这些依赖关系,因此程序员只需要简单地标记响应式元素即可。库的工作是高效地找出哪些响应式函数需要因图中其他地方的变化而运行。在这个例子中,我们的依赖图非常简单:

image.png

响应式库是现代 Web 组件框架(如 Solid、Qwik、Vue 和 Svelte)的核心。在某些情况下,你还可以为其他库(如 Lit 和 React)添加细粒度响应式状态管理。Reactively 提供了一个装饰器,可以为任何类添加响应式属性,并提供了与 Lit 的原型集成。Preact Signals 则提供了与 React 的原型集成。随着这些响应式核心的成熟,预计会有更多的集成方案出现。

响应式库的目标

响应式库的目标是在源发生变化时运行响应式函数。

此外,响应式库还应该:

惰性 vs 即时求值