深入浅出 solid.js 源码 (七)—— 响应式能做什么

2,259 阅读3分钟

这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

上一节看了编译后的逻辑,我们可以发现 createSignal 方法还是原样执行,createSignal 属于 solid.js 响应式更新逻辑的一部分,位于 reactive 目录下,这一部分是 solid.js 运行时的核心逻辑,负责处理 UI 库最重要的事情 —— 同步状态和视图。

这就回到一个最原始的问题,我们为什么要借助工具库来开发,这些视图层开发库给我们带来的是什么?是组件规范吗,是辅助 API 吗?这些可能都不是最重要的,我认为最大的意义还是模型驱动视图。尝试使用原生 API 来开发,对于原始的数据,我们在内存中有一个模型 A,我们把 A 显示在页面上,现在把 A 改成 B,预期结果肯定是希望页面上显示的也是 B,但是现在还是 A,你必须要手动调用修改 DOM 内容的方法来把 A 改成 B。也就是说实际上我们既要修改模型,也要修改视图。现在是只有一个状态 A,如果有多个状态呢,情况就会越发复杂。而现代的 UI 开发库 react、vue 等,都实现了模型和视图的绑定,以 react 为例,我们使用 setState 更新状态数据,组件内使用数据的地方就会自动的更新为新的值,此时我们每次修改只需要关注数据本身而已,这就是状态和视图同步。

接下来一个问题就是,如何知道哪里变了?在 react 中,每次触发 state 数据更新,react 会对 vdom 树进行一个 diff 操作,在 diff 中构建出一个新的 dom 树。vue 有一个数据劫持和绑定的效果,在 vue 更新时会通知 watcher 有变化产生,之后在这个结果的解除之上做 diff。react 和 vue 的区别在于 react 是应用级别全量更新,vue 是组件级别更新,react 根本就不知道更新哪里,因此每次更新时是整个应用的重新 render,vue 由于有 watcher 的存在,它可以知道哪些组件需要变化,对这些变化的组件进行更新。在 react 没有采用 fiber 架构之前,如果优化不合理,页面可能会有性能问题,而 vue 就不会有这种问题。相比而言 vue 可能出现瓶颈的地方是如果 watcher 创建过多可能会造成大量内存占用,造成页面卡顿。

前面提到的 vue 和 react 都不可缺少 diff 的操作,原因在于它们的更新粒度比较大,vue 由于有了一定程度的数据监听,就可以把更新的粒度缩小,那么如果监听粒度更细呢,如果可以精细到每个节点变化都能够监听到,是不是就可以定向更新内容,这时是不是就不需要 diff 了?solid.js 的响应式系统实现的就是这个能力。

这里我们大概了解一下为什么需要响应式更新以及响应式更新是做什么的,接下来会继续深入 solid 源码,看一下 solid 中的响应式是如何实现的。