《React 设计原理》 —— 笔记1

609 阅读6分钟

前言

这是一篇关于卡颂大佬的 《React 设计原理》 书的读后笔记


一、框架概念篇

书中以 “与自变量(即 state)建立对应关系的抽象层” 作为分类依据,划分了三类:

  • 应用级框架:

当 state 更新会触发整个应用发生反应,比如 React 调用一次 setState ,会从当前 Fiber 向上打上优先级,再从最顶层的 FiberRoot 自顶向下调和 Fiber 节点。(注:并不会所有都进行调和,也不会所有都进行 rerender

  • 组件级框架:

当 state 更新会触发整个组件发生反应,比如 Vue ,将 state组件更新方法 进行关联。当更改响应式数据,会调用到 Proxy 里的 set 访问器,进而调用与该数据绑定方法

  • 元素级框架:

当 state 更新仅会触发对应节点发生反应,比如 SvelteSolid.js ,这里简单描述下 Solidjs 也是类似与 Vue 的方式,只不过他是使用了函数闭包返回 getter, setter 的方式构建响应式,且做了些模板编译,将 state与之挂钩的元素 进行关联,使得触发 setter 的时候,只重新处理 与之挂钩的元素 即可

这三类也可以作为 框架更新颗粒度 的分类,颗粒度越细腻,相对应的更新代价越低,性能也就会越好。


二、AOT,JIT 与 VDOM

AOT(Ahead Of Time,预编译)宿主环境(Web 端里泛指浏览器)最终获得的是编译后的代码。

JIT (Just In Time,即时编译)代码在浏览器中编译并执行。

二者区别:

  • 使用 JIT 的应用,在首次加载时慢于使用 AOT 的应用,因为 AOT 在构建时已经完成了编译,可以直接执行。

  • 使用 JIT 的代码体积可能大于 AOT 的应用,因为在运行时会增加编译器代码

【注意】个人感觉编译模式是相对而言的,比如 Js, Python 等脚本语言,几乎都是使用 JIT 的编译模式,而 C/C++ 这类都会提前编译成机器码,再执行,这就属于 AOT ,但我们使用的前端框架,虽然用的也是 Js 但是不能说是 JIT 的。 比如:Svelte 就属于极致的编译时框架,可以从 AOT 中受益。

所谓从 AOT 中受益,即:开发者可以根据自己定义的规则进行一些优化处理,在下面会介绍。

VDOM (Virtual DOM,虚拟 DOM)我们熟知的 Angular,React,Vue 或多或少都有虚拟 DOM 的影子,之所以用虚拟 DOM,也是因为真实 DOM 上有太多不需要开发者关心的属性,如果使用真实 DOM 势必会带来内存上的开销。

一般来说使用模板语法的,基本都为 AOT 框架,能从 AOT 中受益。这里的受益是相对于 VDOM 而言。

大家知道 JSX 使用 Js 来描述 UI, Js 本身就是有逻辑性的,所以其灵活性非常强大, 但也就是由于过分灵活,导致框架的开发者不好对它进行静态分析

而使用固定模板语法来约束用户的行为,便是赋予 Html 逻辑性,让其使用模板语法来描述 UI。这样框架开发者就可以根据预先设定好的规则,对其进行优化。

均衡框架 Vue

我们知道 Vue 既是一种模板语言的框架,又使用了 VDOM ,所以说二者并不是不可兼容的。

Vue 目前的做法是,先通过将模板转换成 render 函数,形成 VNode(虚拟 DOM),最后进行 patch 前后对比 Vnode

我们前面也说了 AOT 可以帮助开发者进行一些静态分析,事实上 Vue 也从其他框架中学习了hoist 静态提升的优化策略,这就是 AOT 的帮助,而又由于 Vue 是组件级框架,所以也使用了 VNode 进行前后对比,来减少对真实 DOM 的操作。

当然 Vue 也快重新迎来无虚拟 DOM 的时代~ 包括 solidjs, svelte 这些元素级框架都不需要使用虚拟 DOM 来提升性能,Vue 接下来应该也是会这么做,达成元素级。

所以说 VDOM 就慢了吗?

当然并不是说使用 VDOM 的就性能一定差,书上举了 blockdom 的例子,该框架在总体性能上和 solidjs 几乎持平。所以并不是 VDOM 慢,而是各个框架使用 VDOM 的方式使得它稍微慢了些。(当然在慢也比操作真实 DOM 来的快)

简单了解了下 blockdom 是将树的节点序列化,这样就不用去挨个节点对比,所以速度会有提升巨大。有兴趣的小伙伴可以查阅下~

极致运行时 React

React 属于极致的运行时框架,由于自身使用的是 JSX 是编译成了 createElement 所以使用的是 VDOM ,而又由于 JSX 本身的特性,愣是一点都没从 AOT 中获取到收益,所以很尴尬,这也就是 React 极致运行时的原因……

当然 React 也尝试过一些思路改变这一现状,尝试过 “将代码编译时的计算结果保留在编译后的代码中,而不是等到运行时再去求值” 当然由于各种原因导致该项目暂停。。

所以说 JSX 的就没办法受益吗?

非也非也~ Solidjs 虽然同样也是使用 JSX,但它又规定了一些内置组件,如果用户使用这些内置组件,那么框架就能从中进行优化,虽然减少了 JSX 的灵活性,但却让性能有了一大提升

具体做法简单说下:

我们 JSX 中会使用 list.map(()=> ()) 方式去循环生成 DOM,而 Solidjs 提供了 For 组件,如果我们使用 For 组件就可以获得性能上的提升,当然该组件写起来,代码会比正常些 JSX 多一丢丢,但是却会获得很好的正向反馈 ———— 这便是通过减少 JSX 灵活性来让代码能从 AOT 中受益。

极致的编译时 Svelte

该框架就详谈了,从头到脚都是模板,完全的 AOT ,极致的编译时~


总结

该笔记为书本第一章的内容。第一章节几乎都是概念性的东西,但书本写的非常好,给的例子也非常 very nice 强烈建议大家购买学习~

另外观察者模式是真滴牛批,我现在看了很多七七八八的,发现很多都用到了这个,不管是 Promise 也好 redux 也好,包括现有的框架也好,所以大家对这个还是要很熟练很熟练,是真滴 very good~