Effect 如果想调度它自身,需要有个排序好的调度表 。Preact 给每个 Effect 实例都添加了专门的 .nextBatchedEffect 属性,让 Effect 实例作为单向调度列表中的节点进行双重作用,这减少了内存抖动,因为反复调度同一个效果不需要额外的内存分配或释放 。
通知订阅和垃圾回收computed signals 实际上并不总是从他们的依赖关系中获取通知的 。只有当有像 effect 这样的东西在监听 signals 本身时,compute signals 才会订阅依赖通知 。这避免了下面的一些情况:
const s = signal(0);{const c = computed(() => s.value)}// c 并不在同一个作用域下如果 c 总是订阅来自 s 的通知,那么 c 无法被垃圾回收,直到 s 也去它这个 scope 上面去 。主要因为 s 会继续挂在一个对 c 的引用上 。
在 Preact Signals 中 , 链表提供了一种比较好的办法去动态订阅和取消订阅依赖通知 。
在那些 computed signal 已经订阅了通知的情况下 , 我们可以利用这个做一些额外的优化 。后面会介绍 computed 懒执行和缓存 。
Computed signals 的懒执行 & 缓存实现懒执行 computed Signals 的最简单方法是每次读取其值时都重新计算 。不过,这不是很高效 。这就是缓存和依赖跟踪需要帮助优化的地方 。
每个普通和 Computed Signals 都有它们自己的版本号 。每次当其值变化时,它们会增加版本号 。当运行一个 compute fn 时 , 它会在 Node 中存储上次看到的依赖项的版本号 。我们原本可以选择在节点中存储先前的依赖值而不是版本号 。然而,由于 computed signals 是懒执行的,这些依赖值可能会永远挂在一些过期或者无限循环执行的 Node 节点上 。因此,我们认为版本编号是一种安全的折中方法 。
我们得出了以下算法 , 用于确定当 computed signals 可以懒执行和复用它的缓存:
- 如果自上次运行以来,任何地方的 signal 的值都没有改变,那么退出 & 返回缓存值 。
- 如果 computed signals 正在监听通知,并且自上次运行以来没有被通知,那么退出 & 返回缓存值 。
- 按顺序重新评估依赖项 。检查它们的版本号 。如果没有依赖项改变过它的版本号,即使在重新评估后,也退出 & 返回缓存值 。
- 运行 compute function 。如果返回的值与缓存值不同,那么递增计算信号的版本号 。缓存并返回新值 。
最后两个步骤经常递归到依赖项中 。这就是为什么早期的步骤被设计为尝试短路递归的原因 。
一些思考JSX 渲染Signal 在 Preact JSX 语法进行传值的时候,可以直接传对应的 Signal 对象而不是具体的值,这样在 Signal 对象的值发生变化的时候,可以在组件不经过重新渲染的情况下触发值的变化(本质上是把 Signal 值绑定到 DOM 值上) 。
例如以下组件:
import { render } from 'preact'import { signal } from '@preact/signals'const count = signal(1);// Component 跳过流程是怎么处理// 可能对 state less 的组件跳过 render(function component)funciton Counter() {console.log('render')return (<><p>Count: {count}</p><button notallow={() => count.value ++}>Add Count</button></>)}render(<TodoList />, document.getElement('App'))
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 浅析营销型网站域名选择技巧
- 浅析Redis数据结构
- 浅析员工流失的原因与解决对策 员工流失的原因及对策
- 百度交易中台之内容分润结算系统架构浅析
- 业务系统常用限流算法浅析
- 浅析 SpringBoot FatJar 机制的设计与实现
- HTTP请求:Requests的进阶使用方法浅析
- Signals大火!为何众多前端主流框架都要实现它?
- 浅析NAS不会被网盘取代的原因
- 浅析 Redis 中 String 数据类型及其底层编码
