javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS SolidJS

基于JavaScript介绍性能爆表的SolidJS

作者:小帅不太帅​​​​​​​

这篇文章主要介绍了基于JavaScript介绍性能爆表的SolidJS,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

前言

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

背景

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

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

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

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

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

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

介绍

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

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

官方给出的理由:

主要优势

对比分析

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

虚拟DOM的分析

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

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

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

核心原理的选择

拿我们熟悉的reactvue说明:

更新粒度的选择

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

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

是否采用虚拟DOM

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

开发语法DSL选择

正文

基本使用

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 <div onClick={handleAdd}>Count value is {count()}</div>;
};
render(() => <CountingComponent />, document.getElementById('app'));

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

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

调用栈分析:

简单分析:

它的响应式实现确实是与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(`<div>Count value is </div>`, 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(() => <App />, 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<ValueType>(null)

  // mount
  onMount(() => {
    request<DataProps>({ method: "GET", url: URL }).then((res) => {
      if (res) {
        console.log("res", res)
        setValue(res)
      }
    })
  })

  // unmount
  onCleanup(() => {
    // ...
  })
  return (
    <div class={cls.App}>
      <Title />
      <List list={getValue()?.list} />
      {getValue()?.pieData && <Chart data={getValue()?.pieData} />}
    </div>
  )
}
export default App

List组件

import type { Component } from "solid-js"
import { ListProps } from "../typings"

import cls from "../index.module.less"

// List
const List: Component<{ list: ListProps[] }> = (props) => {
  return (
    <ul class={cls.list}>
      {props.list?.map(({ label, value }) => (
        <li>
          <div class={cls.label}>{label}</div>
          <div class={cls.value}>{value}</div>
        </li>
      ))}
    </ul>
  )
}
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"

// Chart
const Chart: Component<{ data: OptionProps[] }> = (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 <div ref={container}></div>
}
export default Chart

以上是我基于项目简化的demo,怎么样,看起来是不是和react特别像🤓,使用起来也是相当简单了~

总结

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

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

对于不同类型框架,了解其优势以及一些独有的特殊思路和实现,做到心中有数,也有益于我们的技术成长。

这样我们在之后的实际开发过程中便可结合具体场景做到更合适的技术选型~

到此这篇关于基于JavaScript介绍性能爆表的SolidJS的文章就介绍到这了,更多相关JS SolidJS内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文