前言
这是一篇关于卡颂大佬的 《React 设计原理》 书的读后笔记
一、框架概念篇
书中以 “与自变量(即 state)建立对应关系的抽象层” 作为分类依据,划分了三类:
- 应用级框架:
当 state 更新会触发整个应用发生反应,比如 React
调用一次 setState
,会从当前 Fiber 向上打上优先级,再从最顶层的 FiberRoot 自顶向下调和 Fiber 节点。(注:并不会所有都进行调和,也不会所有都进行 rerender
)
- 组件级框架:
当 state 更新会触发整个组件发生反应,比如 Vue
,将 state
与 组件更新方法 进行关联。当更改响应式数据,会调用到 Proxy
里的 set 访问器
,进而调用与该数据绑定的 方法
- 元素级框架:
当 state 更新仅会触发对应节点发生反应,比如 Svelte
和 Solid.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~