我终于成功登上了JS 框架榜单,并且仅落后于 React 4 名!

news2024/11/22 23:34:47

前言

如期而至,我独立开发的 JavaScript 框架 Strve.js 迎来了一个大版本5.6.2。此次版本距离上次大版本发布已经接近半年之多,为什么这么长时间没有发布新的大版本呢?主要是研究 Strve.js 如何支持单文件组件,使代码智能提示、代码格式化方面更加友好。之前也发布了 Strve SFC,但是由于其语法规则的繁琐以及是在运行时编译的种种原因,我果断放弃了这个方案的继续研究。而这次的版本5.6.2成功解决了代码智能提示、代码格式化方面友好的问题,另外还增加了很多锦上添花的特性,这些都归功于我们这次版本成功支持JSX语法。熟悉React的朋友知道,JSX语法非常灵活。 而 Strve.js 一大特性也就是灵活操作代码块,这里的代码块我们可以理解成函数,而JSX语法在一定场景下也恰恰满足了我们这种需求。

那么,我们如何在 Strve 项目中使用JSX语法呢?我们在Strve项目构建工具 CreateStrveApp 预置了模版,你可以选择 strve-jsx 或者 strve-jsx-apps 模版即可。我们使用 CreateStrveApp 搭建完 Strve 项目会发现,同时安装了babelPluginStrvebabelPluginJsxToStrve,这是因为我们需要使用 babelPluginJsxToStrve 将 JSX 转换为标签模版,之后再使用babelPluginStrve 将标签模版转换为 Virtual DOM,进而实现差异化更新视图。

尝试

我既然发布出了一个大版本,并且个人还算比较满意。那么下一步我如何推广它呢?毕竟毛遂自荐有时候还是非常有意义的。所以,我打算通过js-framework-benchmark 这个项目评估下性能。

js-framework-benchmark 是什么?我们这里就简单介绍下 js-framework-benchmark,它是一个用于比较 JavaScript 框架性能的项目。它旨在通过执行一系列基准测试来评估不同框架在各种场景下的性能表现。这些基准测试包括渲染大量数据、更新数据、处理复杂的 UI 组件等。通过运行这些基准测试,可以比较不同框架在各种方面的性能优劣,并帮助开发人员选择最适合其需求的框架。js-framework-benchmark 项目提供了一个包含多个流行 JavaScript 框架的基准测试套件。这些框架包括 Angular、React、Vue.js、Ember.js 等。每个框架都会在相同的测试场景下运行,然后记录下执行时间和内存使用情况等性能指标。通过比较这些指标,可以得出不同框架的性能差异。这个项目的目标是帮助开发人员了解不同 JavaScript 框架的性能特点,以便在选择框架时能够做出更加明智的决策。同时,它也可以促进框架开发者之间的竞争,推动框架的不断改进和优化。

那么,我们就抱着试试的心态去运行下这个项目。

测试

我们进入js-framework-benchmark Github主页,然后 clone 下这个项目。

git clone https://github.com/krausest/js-framework-benchmark.git

然后,我们 clone 到本地之后,打开 README.md 文件找到如何评估框架。大体浏览之后,我们得出的结论是:通过使用自己的框架完成js-framework-benchmark规定的练习项目。

在这里插入图片描述

那么,我们就照着其他框架已经开发完成的示例进行开发吧!在开发之前,我们必须要了解js-framework-benchmark 中有两种模式。一种是keyed,另一种是non-keyed。在 js-framework-benchmark 中,“keyed” 模式是指通过给数据项分配一个唯一标识符作为 “key” 属性,从而实现数据项与 DOM 节点之间的一对一关系。当数据发生变化时,与之相关联的 DOM 节点也会相应更新。而 “non-keyed” 模式是指当数据项发生变化时,可能会修改之前与其他数据项关联的 DOM 节点。因为 Strve 暂时没有类似唯一标识符这种特性,所以我们选择non-keyed模式。

我们打开项目下/frameworks/non-keyed文件夹,找一个案例框架看一下它们开发的项目,我们选择 Vue 吧!
我们根据它开发的样例迁移到自己的框架中去。为了测试新版本,我们将使用JSX语法进行开发。

import { createApp, setData } from "strve-js";
import { buildData } from "./data.js";

let selected = undefined;
let rows = [];

function setRows(update = rows.slice()) {
  setData(
    () => {
      rows = update;
    },
    {
      name: TbodyComponent,
    }
  );
}

function add() {
  const data = rows.concat(buildData(1000));
  setData(
    () => {
      rows = data;
    },
    {
      name: TbodyComponent,
    }
  );
}

function remove(id) {
  rows.splice(
    rows.findIndex((d) => d.id === id),
    1
  );
  setRows();
}

function select(id) {
  setData(
    () => {
      selected = +id;
    },
    {
      name: TbodyComponent,
    }
  );
}

function run() {
  setRows(buildData());
  selected = undefined;
}

function update() {
  for (let i = 0; i < rows.length; i += 10) {
    rows[i].label += " !!!";
  }
  setRows();
}

function runLots() {
  setRows(buildData(10000));
  selected = undefined;
}

function clear() {
  setRows([]);
  selected = undefined;
}

function swapRows() {
  if (rows.length > 998) {
    const d1 = rows[1];
    const d998 = rows[998];
    rows[1] = d998;
    rows[998] = d1;
    setRows();
  }
}

function TbodyComponent() {
  return (
    <tbody $key>
      {rows.map((item) => (
        <tr
          class={item.id === selected ? "danger" : ""}
          data-label={item.label}
          $key
        >
          <td class="col-md-1" $key>
            {item.id}
          </td>
          <td class="col-md-4">
            <a onClick={() => select(item.id)} $key>
              {item.label}
            </a>
          </td>
          <td class="col-md-1">
            <a onClick={() => remove(item.id)} $key>
              <span
                class="glyphicon glyphicon-remove"
                aria-hidden="true"
              ></span>
            </a>
          </td>
          <td class="col-md-6"></td>
        </tr>
      ))}
    </tbody>
  );
}

function MainBody() {
  return (
    <>
      <div class="jumbotron">
        <div class="row">
          <div class="col-md-6">
            <h1>Strve-non-keyed</h1>
          </div>
          <div class="col-md-6">
            <div class="row">
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="run"
                  onClick={run}
                >
                  Create 1,000 rows
                </button>
              </div>
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="runlots"
                  onClick={runLots}
                >
                  Create 10,000 rows
                </button>
              </div>
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="add"
                  onClick={add}
                >
                  Append 1,000 rows
                </button>
              </div>
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="update"
                  onClick={update}
                >
                  Update every 10th row
                </button>
              </div>
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="clear"
                  onClick={clear}
                >
                  Clear
                </button>
              </div>
              <div class="col-sm-6 smallpad">
                <button
                  type="button"
                  class="btn btn-primary btn-block"
                  id="swaprows"
                  onClick={swapRows}
                >
                  Swap Rows
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
      <table class="table table-hover table-striped test-data">
        <component $name={TbodyComponent.name}>{TbodyComponent()}</component>
      </table>
      <span
        class="preloadicon glyphicon glyphicon-remove"
        aria-hidden="true"
      ></span>
    </>
  );
}

createApp(() => MainBody()).mount("#main");

其实,我们虽然使用了JSX语法,但是你会发现有很多特性并不与JSX语法真正相同,比如我们可以直接使用 class 去表示样式类名属性,而不能使用 className 表示。

评估案例项目开发完成了,我们下一步就要测试一下项目是否符合评估标准。

npm run bench non-keyed/strve

在这里插入图片描述

测试标准包括:

  • create rows:创建行,页面加载后创建 1000 行的持续时间(无预热)

  • replace all rows:替换所有行,替换表中所有 1000 行所需的时间(5 次预热循环)。该指标最大的价值就是了解当页面上的大部分内容发生变化时库的执行方式。

  • partial update:部分更新,对于具有 10000 行的表,每 10 行更新一次文本(进行 5 次预热循环)。该指标是动画性能和深层嵌套数据结构开销等方面的最佳指标。

  • select row:选择行,在单击行时高亮显示该行所需的时间(进行 5 次预热循环)。

  • swap rows:交换行,在包含 1000 行的表中交换 2 行的时间(进行 5 次预热迭代)。

  • remove row:删除行,在包含 1,000 行的表格上移除一行所需的时间(有 5 次预热迭代),该指标可能变化最少,因为它比库的任何开销更多地测试浏览器布局变化(因为所有行向上移动)。

  • create many rows:创建多行,创建 10000 行所需的时间(没有预热),该指标更容易受到内存开销的影响,并且对于效率较低的库来说,扩展性会更差。

  • append rows to large table:追加行到大型表格,在包含 10000 行的表格上添加 1000 行所需的时间(没有预热)。

  • clear rows:清空行,清空包含 10000 行的表格所需的时间(没有预热),该指标说明了库清理代码的成本,内存使用对这个指标的影响很大,因为浏览器需要更多的 GC。

最终,Strve 顶住了压力,通过了测试。

看到了successful run之后,觉得特别开心!那种成就感是任何事物都难以代替的。

跑分

我们既然通过了测试,那么下一步我们将与前端两大框架Vue、React进行比较跑分,我们先在我自己本地环境上跑一下,看一下效果。

性能测试基准分为三类:

  • 持续时间
  • 启动指标
  • 内存分配

持续时间

在这里插入图片描述

启动指标
在这里插入图片描述

内存分配

在这里插入图片描述

总体而言,我感觉还不错,毕竟跟两个大哥在比较。到这里我还是觉得不够,跟其他框架比比呢!

提交

只要框架通过了测试,并且按照提交PR的规定提交,是可以被选录到 js-framework-benchmark 中去的。

好,那我们就去试试!

在这里插入图片描述

又一个比较有成就感的事!提交的PR被作者合并了!

成绩单

我迫不及待的去榜单上看下我的排名,会不会垫底啊!

因为浏览器版本发布的时差问题,暂时 Official results ( 官方结果 ) 还没有发布最新结果,我们可以先来 Snapshot of the results ( 快照结果 ) 中查看。

我们打开下方网址就可以看到JS框架的最新榜单了。

https://krausest.github.io/js-framework-benchmark/current.html

我们在持续时间这个类别下从后往前找,目前63个框架我居然排名 50 名,并且大名鼎鼎的 React 排名45名。

在这里插入图片描述

我们先不激动,我们再看下启动指标类别。Strve 平均分数是1.04,我看了看好几个框架分数是1.04。Strve 可以排到前8名。
在这里插入图片描述

我们再稳一下,继续看内存分配这个类别。Strve 平均分数是1.40,Strve 可以排到前12名。

在这里插入图片描述

意义

js-framework-benchmark 的测试结果是相对准确的,因为它是针对同样的测试样本和基准测试情境进行比较,可以提供框架之间的相对性能比较。然而,需要注意的是,这个测试结果也只是反映了测试条件下的性能表现。框架实际的性能可能还会受到很多方面的影响。
此外,js-framework-benchmark 测试结果也不应该成为选择框架的唯一指标。在选择框架时,还需要考虑框架的生态、开发效率、易用性等多方面因素,而不仅仅是性能表现。

虽然,Strve 跟 React 比较是有点招黑,但是不妨这样想,榜样的力量是巨大的!只有站在巨人的肩膀上才能望得更远!

Strve 要走的路还有很长,入选JS框架榜单使我更加明确了方向。我觉得做自己喜欢做得事情,这样才会有意义!

加油

Strve 要继续维护下去,我也会不断学习,继续精进。

Strve 源码仓库:https://github.com/maomincoding/strve

Strve 中文文档:https://maomincoding.gitee.io/strve-doc-zh/

谢谢大家的阅读!如果大家觉得Strve不错,麻烦帮我点下Star吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[洛谷]P8662 [蓝桥杯 2018 省 AB] 全球变暖(dfs)

读题不规范&#xff0c;做题两年半&#xff01; 注意&#xff1a;被海水淹没后的陆地应用另一个字符表示&#xff0c;而不是把它变为海洋&#xff0c;这个点可以便利&#xff0c;但不能被当作起点&#xff0c;不然就只有 36 分。 ACocde: #include<bits/stdc.h> using…

nodejs 下载地址 阿里云开源镜像站

nodejs 下载地址 阿里云开源镜像站 https://mirrors.aliyun.com/nodejs-release/ 我们下期见&#xff0c;拜拜&#xff01;

STM32(HAL库)通过ADC读取MQ2数据

目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 ADC外设配置 2.3 串口外设配置 2.4 项目生成 3、KEIL端程序整合 3.1 串口重映射 3.2 ADC数据采集 3.3 主函数代 3.4 效果展示 1、简介 本文通过STM32F103C8T6单片机通过HAL库方式对M…

【java】JMeter进行web测试

JMeter进行web测试 1.对网页进行负载测试新建线程组添加默认 HTTP 请求属性添加cookie支持添加HTTP请求添加监听器以便于查看结果登录网站 2. 测试本地web项目3. 其他使用 URL 重写处理用户会话使用标题管理器 参考JMeter用户手册 https://jmeter.net/usermanual/build-web-te…

PC与(VMware)linux的IP互通

一、环境 二、NAT模式 NAT&#xff08;Network Address Translation&#xff09;网络地址转换&#xff0c;允许一个整体机构以一个公用IP地址出现在Internet上&#xff0c;即把内部私有网络地址翻译成合法网络IP地址的技术。家用路由器一般都是NAT模式。让虚拟系统借助NAT&…

14、vivado打不开工程源码

卡在Initializing Language Server. 解决办法&#xff1a;下图&#xff0c;然后重启软件

微软开源了一个 助力开发LLM 加持的应用的 工具包 semantic-kernel

在首席执行官萨蒂亚纳德拉&#xff08;Satya Nadella&#xff09;的支持下&#xff0c;微软似乎正在迅速转变为一家以人工智能为中心的公司。最近微软的众多产品线都采用GPT-4加持&#xff0c;从Microsoft 365等商业产品到“新必应”搜索引擎&#xff0c;再到低代码/无代码Powe…

数学分析:面积和微分形式

这是面积的推广&#xff0c;这里引出了格拉姆矩阵&#xff0c;有了这个&#xff0c;我们得到的矩阵总是方阵&#xff0c;可以绕过雅可比矩阵不存在的问题。能得到通用的积分换元公式。 其实任何时候&#xff0c;从几何意义去理解总是更加自然。考虑一个平面上的坐标&#xff0c…

centos7安装 mongodb

一、rpm安装 1.1、配置MongoDB Enterprise的yum 源文件 [mongodb-enterprise] nameMongoDB Enterprise Repository baseurlhttps://repo.mongodb.com/yum/redhat/$releasever/mongodb-enterprise/3.4/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://www.mongodb.org/static/pgp…

数据结构(王道)——数据结构之 串

一、串的数据结构 串的定义&#xff1a; 串和线性表对比&#xff1a; 串的基本操作 串的比较思路 字符集编码含义 串定义总结&#xff1a; 二、串的存储结构 定义一个串的方式 定长顺序存储和堆分配存储 定长顺序存储的方案&#xff1a; 堆分配存储的方案&#xff1a; 基本操…

vscode远程连接提示:过程试图写入的管道不存在(删除C:\Users\<用户名>\.ssh\known_hosts然后重新连接)

文章目录 复现过程原因解决方法总结 复现过程 我是在windows上用vscode远程连接到我的ubuntu虚拟机上&#xff0c;后来我的虚拟机出了点问题&#xff0c;我把它回退了&#xff0c;然后再连接就出现了这个问题 原因 本地的known_hosts文件记录服务器信息与现服务器的信息冲突了…

Spring MVC异常处理【单个控制异常处理器、全局异常处理器、自定义异常处理器】

目录 一、单个控制器异常处理 1.1 控制器方法 1.2 编写出错页面 1.3 测试结果 二、全局异常处理 2.1 一个有异常的控制器类 2.2 全局异常处理器类 2.3 测试结果 三、自定义异常处理器 3.1 自定义异常处理器 3.2 测试结果 往期专栏&文章相关导读 1. Maven系列…

【并发编程二十二】通过进程名字杀死进程TerminateProcess

【并发编程二十二】通过进程名字杀死进程TerminateProcess 一、代码二、杀进程失败时&#xff0c;检查1、OpenProcess的参数2、UpdatePrivilege提升优先级3、以管理员方式&#xff0c;启动进程 三、启动进程失败1、由于找不到vcruntime140d.dll&#xff0c;无法继续执行代码。2…

ScaleBit 与 NFTScan 达成安全生态合作伙伴关系

7 月初&#xff0c;ScaleBit 与 NFT 基础设施服务商 NFTScan 正式达成安全生态战略合作&#xff0c;携手促进 NFT 生态的安全性。 NFTScan 作为全球领先的 NFT 基础设施服务商&#xff0c;旨在为 Web3 用户和开发者提供专业的一站式 NFT 基础设施服务。用户可以通过它搜索、查看…

3. CSS-定位

absolute和relative依据什么定位? relative依据自身定位,absolute 依据最近一层的定位元素定位 (定位元素是指开启了absolute relative fixed的父元素,没有就是根元素body) 居中对齐的实现方式:详情看这篇博客

10、添加osmbuilding全球建筑模型

本节演示使用CCesium库添加osm的全球建筑模型。在第四节的例子中修改。 1、修改鼠标点击事件&#xff0c;创建osmbuilding并添加到地图中。 aggregator->tileset Cesium::CreateOsmBuildings::createOsmBuildings(false); aggregator->viewer->_scene->primitiv…

linux中安装minio

在 opt 下创建 minio 目录 mkdir minio 上传安装包到 /opt/minio 目录 进入目录 cd minio 授权minio chmod 777 minio 启动minio nohup ./minio server --address 0.0.0.0:9000 --console-address 0.0.0.0:9090 /opt/minio/data > /opt/minio/minio.log 2>&1…

Nautilus Chain NautDID NFT 将上主网,Layer3 数字身份时代开启

Nautilus Chain 是行业内首个模块化 Layer3 链&#xff0c;其采用Celestia模块化底层&#xff0c;并通过ZK Rollup 技术来增加隐私。Nautilus Chain 允许开发者以定制化的方式&#xff0c;通过 Nnautilus 开发者可以更广泛化的在一揽子的模块中&#xff0c;选择适合自己的方案&…

1、shell脚本的基本知识——变量、字符串、循环

目录 一、基本知识 二、 shell的变量和赋值 1、注意 2、变量的种类 3、例子 三、特殊符号 1、单引号、双引号、反引号 2、管道 3、大于号>和小于号<(重定向) &#xff08;1&#xff09;常识 &#xff08;2&#xff09;应用&#xff08;描述符在右边的时候&#x…

JavaWeb(6)——前端工程化(AJAX 和VUE入门)

一、AJAX快速入门 而原生的Ajax请求的代码编写起来还是比较繁琐的&#xff0c;所以接下来我们学习一门更加简单的发送Ajax 请求的技术Axios 。Axios是对原生的AJAX进行封装&#xff0c;简化书写。 Axios官网是&#xff1a;起步 | Axios 中文文档 | Axios 中文网 (axios-http.c…