Signal 的出现

在 2020 年Vue.js 3发布时,Vue.js 3 推动了前端框架中 Signal 模式的流行,SolidJS 进一步强化了这一趋势,促使 Angular 和 Svelte 等也采用类似机制。

在 2010 年的时候,knockout;js 已经使用了类似 Signal 形式的机制。

虽然 Signal 模式并非由 Vue 首创,但 Vue 是第一个大规模使用 Signal 进行UI更新的主要框架。在 Vue 中,Signal 被称为 refs。通过设置 refs 并在模板中引用它们,当 refs 的值发生变化时,UI 中相应的部分会自动更新。这就是 Signal 背后的理念

随着 SolidJS 的采用,Signal 变得非常流行。尽管 SolidJS 是一个较小的前端JavaScript框架,但它使得 Signal 概念广为人知。SolidJS 强调细粒度的响应式更新,只有当数据变化时,UI中真正变化的部分才会更新,这使得 Signal 变得非常受欢迎。

Angular 也引入了 Signal,Angular 现在允许使用 Signal 来管理状态并更新 UI。Svelte 引入了称为runes 的 Signal,用于 UI 更新管理。显然,Signal 已经成为前端开发的一个普遍概念。

Signal 之所以流行,是因为它们允许框架提供细粒度的响应式,这可以带来更高的效率和更好的性能。那么Signal究竟是如何工作的呢?

Signal 是如何工作的

Signal = Data + Update Function + Subscribers

Signal 就是一些数据和一些可能更新这些数据的函数,结合一个订阅者列表,这些订阅者对数据变化感兴趣,以便在数据变化时得到通知。

Snipaste_2024-12-08_21-23-02.png

构建最简易的 Signal

我们可以从一个管理数据并创建两个内部函数的函数开始:一个函数返回最新的数据,另一个函数用于将数据设置为新值。

创建 Signal 函数时,还接受一个初始值,以便将内部管理的数据设置为初始值。

export const createSignal = initialValue => {
  let value = initialValue

  const read = () => {
    return value
  }

  const set = newValue => {
    value = newValue
  }

  return [read, set]
}

然后我们可以使用 createSignal 函数创建多个 Signal,它们都有自己的数据。我们可以使用 read 函数读取这些值,使用 set 函数更新这些值,然后读取更新后的值。

import { createSignal } from './signal.js'

const [count, setCount] = createSignal(10)
const [count2, setCount2] = createSignal(0)

console.log(count()) // reading

setCount(100) // updating value