性能爆表的SolidJs(性能爆表的纸飞机)

您所在的位置:网站首页 templatejs预渲染 性能爆表的SolidJs(性能爆表的纸飞机)

性能爆表的SolidJs(性能爆表的纸飞机)

2023-02-23 12:51| 来源: 网络整理| 查看: 265

作者:前端小帅

博客:https://ssscode.com/pages/1c6866/

使用预编译、无虚拟DOM、究极融合怪、性能爆表、React的异父异母亲兄弟——SolidJs

背景

前段时间,产品提了个临时需求,让我给开发一个独立部署的首页可视化页面,因为目前我们系统提供以iframe的方式实现用户自己选择URL配置一个页面,作为应用的其中一个路由页面使用~

想着就单独部署一个页面,也没必要使用React或者Vue了,简单画个页面完事,jq我是用不动了

想着最近社区也涌现了不少有趣的框架,之前看svelte,就觉得挺有意思的,感觉也比较符合我的使用场景,正准备用这个上手搞一波呢

然后,在GitHub发现了solidjs这个项目,大致看了下,好家伙,这简直比react还react😆~

看了下文档,写了demo试了下,很容易上手,又看了一些对比测试和博客介绍,感觉性能很强啊,和svelte一样都是预编译,没有运行时,构建产物十几kb,与原生js相差无几,令人惊叹~

对于我这种小项目还是比较适合的~

不多逼逼,直接上手干🧐🧐~

介绍

官方介绍:用于构建用户界面的声明式、高效且灵活的 javaScript

Solid 使用了类似 Svelte 的预编译,语法使用上类似于 React,使用 JSX 语法和非常相像的API,但不同于 React,组件只会初始化一次,并不是 state 改变就重新运行渲染整个组件,这类似于 Vue3 的 setup和响应式更新(更新颗粒度为节点级)

官方给出的理由:

高性能 – 始终在公认的 UI 速度和内存利用率基准测试中名列前茅 强大 – 可组合的反应式原语与 JSX 的灵活性相结合 务实 – 合理且量身定制的 API 使开发变得有趣而简单 生产力 – 人体工程学和熟悉程度使构建简单或复杂的东西变得轻而易举 主要优势 高性能 – 接近原生的性能,在 js-framework-benchmark 排名中名列前茅 极小的打包体积 – 编译为直接的DOM操作,无虚拟DOM,极小的运行时(类似于 Svelte),适合做为独立的 webComponent 在其它应用中嵌入 易于使用 – 近似 React 的使用体验,便于快速上手

性能爆表的SolidJsSolidJs-time

性能爆表的SolidJsSolidJs-TPS 对比分析

我们把关注点聚焦于是否使用虚拟DOM,以及数据的响应处理。

虚拟DOM的分析

首先,虚拟DOM并不是一定比原生性能好,或者说是更快,抛开真实场景不谈都是瞎扯淡,框架的设计和应用场景是有它自身考量的。

在状态与Dom操作之间抽象出一层虚拟Dom,需要牺牲一定的运行时性能,并不一定比直接操作原生Dom快,要看情况,毕竟diff并不是免费的。

不管你的数据变化多少,每次重绘的性能都是可以接受(提供过的去的性能)。 你依然可以用类似 innerHTML 的思路去写你的应用。 最最重要的一点,实现了跨平台。

如react,对于web端的渲染可以使用react-dom,对于native的渲染可以使用react-native、以及服务端渲染等,他们的开发模式非常类似,按照react的语法规则进行即可,但是在render层,只要符合react api规范,你可以提供各种不同的render渲染函数,进行跨平台的渲染实现。

核心原理的选择

拿我们熟悉的react和vue说明:

React对数据的处理是不可变(immutable):具体表现是整树更新,更新时,不关注是具体哪个状态变化了,只要有状态改变,直接整树diff找出差异进行对应更新。 Vue对数据的处理是响应式、可变的(mutable):更新时,能够精确知道是哪些状态发生了改变,能够实现精确到节点级别的更新(类似的框架还有Svelte、SolidJS)。 更新粒度的选择 应用级:有状态改变,就更新整个应用,生成新的虚拟Dom树,与旧树进行Diff(代表作:React,当然了,现在它的虚拟Dom已升级为了Fiber)。 组件级:与上方类似,只不过粒度小了一个等级(代表作:vuev2及之后的版本)。 节点级:状态更新直接与具体的更新节点的操作绑定(代表作vue1.x、Svelte、SolidJS)。

vue1.x时代,对于数据是每个生成一个对应的Wather,更新颗粒度为节点级别,但这样创建大量的Wather会造成极大的性能开销,因此在vue2.x时代,通过引入虚拟DOM优化响应,做到了组件级颗粒度的更新。

而对于react来说,虚拟DOM就是至关重要的部分,甚至是核心,我们已经了解react是属于应用级别的更新,因此整个DOM树的更新开销是极大的,所以这里对于虚拟DOM+diff算法的使用就是极其必要的。包括现在的fiber架构与可中断更新,也算是对虚拟DOM的极致压榨。

是否采用虚拟DOM

这个选择是与上边采用何种粒度的更新设计紧密相关的:

是:对应用级的这种更新粒度,虚拟Dom简直是必需品,因为在diff前它并不能得到此次更新的具体节点信息,必须要通过随后的虚拟Dom+Diff算法筛选出最小差异,不然整树append对性能是灾难(代表框架:React、vue)。 但这里值得注意的事是:本质上vue并不需要虚拟DOM,因为它这种基于依赖收集的响应式机制可以直接进行节点级更新,但vue借助虚拟DOM的抽象能力,可以做到更新粒度的随意调整(目前是组件级),给vue的发展提供更多可能性, 尤其在跨平台渲染方面,这点十分关键。 否:对节点级更新粒度的框架来说,一般没有必要采用虚拟dom(代表作:vue1.x、Svelte、SolidJS)。 开发语法DSL选择 JSX:React、SolidJS 模版+编译指令:vue(JSX可选)、Svelte 正文 基本使用 import { render } from 'solid-js/web';import { createSignal, createEffect } from 'solid-js';const CountingComponent = () => {  const [count, setCount] = createSignal(0);  createEffect(() => console.log('count', count()));  const handleAdd = () => {    setCount((prev) => prev + 1);  };  return Count value is {count()};};render(() => , document.getElementById('app'));

这简直是React hooks的双胞胎兄弟…

而且因为SolidJS这种后发优势,没有React沉重的历史包袱,比如不需要处理类组件的兼容(SolidJS只支持函数式)这让它在实现了大部分React功能特性的前提下,源码体积要比React小很多,这让它在首屏加载方面就首先占据上风。直接调用编译好的DOM操作方法,省去了虚拟DOM比较这一步所消耗的时间,整个更新链路相比React变得简洁许多。

调用栈分析:

性能爆表的SolidJssolidjs-1

性能爆表的SolidJssolidjs-2

简单分析:

组件函数只会在整个应用生命周期里调用一次。 心智模型与React完全不一样,反而与vue3保持了一致,可以说兼具了React hooks + vue3的优点 createEffect自动追踪依赖,不需要像react那样维护一个dep数组 hook调用顺序没要求,以函数调用的方式解决Proxy目标必须是对象的问题

它的响应式实现确实是与vue一样,都是基于发布订阅的依赖收集去做的,但它没有采用vue虚拟Dom的运行时diff,而是充分在编译阶段做文章,将状态更新编译为独立的DOM操作方法。

编译内容分析 import { render, createComponent, delegateEvents, insert, template } from 'solid-js/web';import { createSignal, createEffect } from 'solid-js';const _tmpl$ = /*#__PURE__*/template(`Count value is `, 2);const CountingComponent = () => {  const [count, setCount] = createSignal(0);  createEffect(() => console.log('count', count()));  const handleAdd = () => {    setCount(prev => prev + 1);  };  return (() => {    const _el$ = _tmpl$.cloneNode(true);          _el$.firstChild;    _el$.$$click = handleAdd;    insert(_el$, count, null);    return _el$;  })();};render(() => createComponent(CountingComponent, {}), document.getElementById('app'));delegateEvents(["click"]);

可以看到,跟基于 Virtual DOM 的框架相比,这样的输出不需要 Virtual DOM 的 diff/patch 操作,自然可以省去大量的运行时代码。而是使用了solid-js/web库提供的insert等DOM函数操作。

再结合以后的webcomponent考虑下,真是大有可为,发展空间很大,未来可期~

项目实战

直接按照官方文档示例,创建一个支持TypeScript的基础项目,模板默认使用vite构建(solidjs-templates)

# Typescript template$ npx degit solidjs/templates/ts my-solid-project$ cd my-solid-project$ npm install # or pnpm install or yarn install

在vite中引入插件

import solidPlugin from "vite-plugin-solid"export default defineConfig({  plugins: [solidPlugin()],})

入口文件配置如下:

import { render } from "solid-js/web"import App from "./App"render(() => , document.getElementById("root"))

接下来就可以开始写业务代码了,就是这么简单~

import { Title, List, Chart } from "./components"import { onMount, onCleanup, createSignal } from "solid-js"import request from "./utils/request"import type { Component } from "solid-js"import type { DataProps, ValueType } from "./typings"import cls from "./index.module.less"const URL = "/statistic/hrm"const App: Component = () => { const [getValue, setValue] = createSignal(null) // mount onMount(() => { request({ method: "GET", url: URL }).then((res) => { if (res) { console.log("res", res) setValue(res) } }) }) // unmount onCleanup(() => { // ... }) return ( {getValue()?.pieData && } )}export default App

List组件

import type { Component } from "solid-js"import { ListProps } from "../typings"import cls from "../index.module.less"// Listconst List: Component = (props) => { return ( {props.list?.map(({ label, value }) => ( {label} {value} ))} )}export default List

Echart可视化组件

import { onMount, onCleanup } from "solid-js"import type { Component } from "solid-js"import echarts, { ECOptionPie } from "../../utils/echart"import { OptionProps } from "../../typings"// Chartconst Chart: Component = (props) => { let container: null | HTMLDivElement = null let instance // 性别分布 const Option: ECOptionPie = { // data: props.data || [], // ... } onMount(() => { instance = echarts.init(container) instance.setOption(Option) window.addEventListener("resize", () => instance?.resize()) }) onCleanup(() => { window.removeEventListener("resize", () => instance?.resize()) }) return }export default Chart

怎么样,看起来是不是和react特别像🤓,使用起来也是相当简单了~

总结

自react和虚拟DOM诞生以来,整个前端的开发范式都发生了翻天覆地的变化,各种类似框架也是层出不穷,他们各有各的优势。

对我们开发者来说,对于同一类型框架熟练掌握一种足矣,大可不必每种框架都学习一遍,我们需要做到对其内部实现原理的知悉,做到知其然也知其所以然,正所谓一法通万法皆通,当我们打牢基础之后再去使用和学习其他框架便轻而易举了,并在实践中拓展知识广度和深度。

参考 SolidJs SolidJS硬气的说:我比React还react Solid-js 基础教程 你听说过 No DomDiff 吗?

原文始发于微信公众号(前端小帅):性能爆表的SolidJs

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/114506.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3