又一个前端框架 Solid ?性能直逼原生 JS ?
共 2607字,需浏览 6分钟
·
2021-08-24 18:05
到底有多快,我们看看 Benchmark
原生 JS 是 1, Solid 1.05, 比 Svelte 也快,React 跑到了 1.93 。为什么这么快?让我们来揭开神秘的面纱。官方也提供了 playground,可以实时看到打包后的代码,不如上去动手感受一下~
首先,官方代码如下:
import { render } from "solid-js/web";
import { createSignal, createEffect, createMemo, mapArray } from "solid-js";
function CounterNum() {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
createEffect(() => {
console.log("i am alive");
});
return (
<>
<button type="button" onClick={increment}>
{count()}
</button>
</>
);
}
这个代码,看起来,可以说跟 React Hook 一毛一样了,可以理解,也期望以后新创建的框架,都可以往 React 等框架语法靠拢。而不是又创建一套新的语法。真的学不动啊,程序员不要内卷程序员。这点 Solid 框架作者就做得不错。
那为什么快,猜测有三点:
直接使用浏览器的 DOM, 没有虚拟 DOM, DOM diff 一整套算法 响应式原理,精准更新对应的值 提前编译,更小的包体积,尺寸小
一、 直接使用浏览器的 DOM, 没有虚拟 DOM, DOM diff 一整套算法
我们看一下他编译出来的代码,可以发现,他的 DOM ,是原生 DOM ,其他的语法是直接调用的,也没有那一整套复杂的虚拟 DOM
二、提前编译,按需打包
无论是 react 还是 vue ,不管怎么编译,都需要引入框架本身。也就是 runtime 。而且这个体积还比较大。这些框架都采用的是用运行时方案,运行时方案相比于编译时方案,最大的优势是可以「几乎没有任何语法约束」的去完成代码编写。而 Solid 则预编译,将 jsx 部分的代码,转换成原生的语法。
我们直接看代码, 如果把对应的 click 事件去掉,看看 build 之后的代码是怎么样的。
可以看到,delegateEvents(["click"]); 这一行代码不见了,也不会引入 delegateEvents 这个方法。这个特性非常厉害,这样可以得到最小的包体积。
三、响应式原理,精准更新对应的值
如果了解 React 的原理,就会知道,只要是 props 或者 state 改变,React 组件就会重新渲染,而每一次判断是否会重新改变,值是否不一样,也是一整套算法…… Solid 不一样,他另辟蹊径,每一个组件都是一个独立的线程,每个组件里的 createMemo 或 createEffect 里面去收集对应的依赖, 在 set 改变值后,都会重新执行这些方法。看起来就像是实时更新了一样。
核心的原理可以用下面两段代码来展示:
从这两段代码,他就可以实现,当 value 值改变时,会自动重新渲染 createMemo,createEffect 里的方法,自动更新 DOM 对应的值。响应式变化。
如果还是不理解的话,可以看一下下面这张图,其实就是使用了 发布-订阅方式:
关键的步骤如下:
createeffect 分析依赖还有回调,存入全局变量 read 的时候,如果有这个依赖对应的值,则放入 subscriptions。为什么这里需要使用 {count()} 函数才能读取值也是因为这期间要处理一些事情。 write 的时候,去 subscriptions 里面触发对应的函数
总结
我们分析了 Solid
为什么性能这么快,主要从下面三个方面来讲:
直接使用浏览器的 DOM, 没有虚拟 DOM, DOM diff 一整套算法 响应式原理,精准更新对应的值 提前编译,更小的包体积,尺寸小
学习借鉴下原理挺不错的,在生产环境中使用还是算了,毕竟一个新框架前期正处于快读迭代的过程中,肯定会有一堆弃用的api。且他的生态距离 react,vue 的生态,还需要发展几年。选用一个框架,如果考量他的性能,也要考量可维护性,编码效率等…
前端的技术发展,从原生 DOM ,到虚拟 DOM,随着浏览器自身性能越来越好,以后会不会又回归到 原生 DOM