type
status
date
slug
summary
tags
category
icon
password
Edited
Dec 8, 2024 02:00 PM
Created
Dec 8, 2024 09:07 AM
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 就是一些数据和一些可能更新这些数据的函数,结合一个订阅者列表,这些订阅者对数据变化感兴趣,以便在数据变化时得到通知。
构建最简易的 Signal
我们可以从一个管理数据并创建两个内部函数的函数开始:一个函数返回最新的数据,另一个函数用于将数据设置为新值。
创建 Signal 函数时,还接受一个初始值,以便将内部管理的数据设置为初始值。
然后我们可以使用
createSignal
函数创建多个 Signal,它们都有自己的数据。我们可以使用 read
函数读取这些值,使用 set
函数更新这些值,然后读取更新后的值。但现在,我们还没有得到真正的响应性。当我们将 Signal 设置为新值时,使用它的部分并没有得到通知。
我们可以通过管理一个订阅者列表来改变这一点,这个列表可以是一个简单的数组或集合。有了订阅者数组,我们可以在
read
函数中将新的订阅者推入订阅者数组。这就是为什么 read
函数必须是一个函数,以及为什么我们不在 createSignal
函数中直接返回 Signal 值的原因。因为我们需要知道谁在读取,并把代码中的那部分添加到订阅者中。在
set
函数中,我们遍历所有订阅者,并假设每个订阅者都是一个可以调用的函数,以通知订阅者 Signal
值已更改,并让订阅者再次执行它们想要对 Signal
执行的操作。我们的假设是,最终订阅者是一个函数,我们需要在读取 Signal
时添加那个订阅者函数。还需要创建一个单独的
effect
函数,然后可以使用它来包装任何读取 Signal 的代码,这样你就可以在不传递函数给 read
函数的情况下读取。effect
函数的简单想法是,它接受一个应该在读取的 Signal 变化时重新执行的函数。这是通过在 effect
函数内部更新一个全局变量并将其设置为 effect
函数来实现的,然后调用 read
。在
read
函数中,我们然后访问那个全局变量以获取当前执行的 effect
函数,并将当前执行的 effect
函数(存储在全局变量中)添加到订阅者数组中。通过这种方式,我们可以在代码中任意次数使用
effect
函数来注册一个函数,该函数将在读取的 Signal
变化时重新执行。read
函数将被执行并将其自身添加到其订阅者中,因为它是在 effect
函数中执行的 read
函数,我们确保在更新这个全局变量后执行 effect
函数。因此,
effect
函数在那里执行,read
函数执行,read
函数访问那个全局变量,它指的是当前正在执行的 effect
函数,并将其添加到订阅者列表中。这就是我们如何确保所有这些
effect
函数都被添加到订阅者列表中,以及理解 Signal 内部是如何工作的。完整代码
Signal 机制的核心是使用函数而非直接返回值来管理数据,通过
read
和 set
函数分别获取和设置值,并维护订阅者列表以实现数据变更时的自动更新。 这需要将读取函数设计为函数而非直接返回信号值,以便追踪和管理订阅者,从而实现高效的UI更新。总结
本文的概念,解释了 Signal 的原由以及如何工作的,同时构建了一个最简易的 Signal 库。
当然,如前所述,这些框架更加高级,并且以更有效的方式执行此操作,并提供额外的功能。例如,它们还允许你在模板中使用 Signal,并且它们会自动为你包装这样的 effect 函数。
希望这篇文章能帮助你更好地理解信号的概念及其在前端开发中的应用!Singal 的引入使得状态管理和 UI 更新变得更加高效,值得开发者深入学习和应用。
参考链接
- 作者:JinSo
- 链接:https://jinso365.top/156cee950faf8044b751e6c52f3c4258
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。