自研框架跻身全球 JS 框架榜单,排名紧随 React、Angular 之后!

本文主要是介绍自研框架跻身全球 JS 框架榜单,排名紧随 React、Angular 之后!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

终于实现了一个重要目标!我独立研发的 JavaScript 框架 Strve,最近发布了重大版本 6.0.2。距离上次大版本发布已经接近两个月,期间进行了大量的优化,使得框架性能和稳定性都得到了大幅度的提升。在上次的大版本更新中,成功实现了对 JSX 语法的全面支持,使得 Strve 在代码智能提示和代码格式化方面更加友好,进一步提高了开发效率。

介绍

相信有些小伙伴没有听说过 Strve 到底是什么,那我这里就大体介绍一下。

Strve 是一个可以将字符串转换为视图(用户界面)的 JavaScript 库。Strve 不仅易于使用,而且可以灵活地拆解不同的代码块。使用模板字符串开发用户界面,主要是利用 JavaScript 的能力,只关注 JavaScript 文件。Strve 又是一个易用性的 JavaScript 框架,它提供了很多实用的功能与生态工具。

我们可以通过一些简单的示例来了解 Strve 的使用方法。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>Strve.js</title></head><body><script src="https://cdn.jsdelivr.net/npm/strve-js@6.0.2/dist/strve.full.prod.js"></script><script>const { html, setData, createApp } = Strve;const state = {count: 0,};function add() {setData(() => {state.count++;});}function App() {return html`<h1 onClick=${add}>${state.count}</h1>`;}const app = createApp(App);app.mount('#app');</script></body>
</html>

在上述代码中,我们通过引入 Strve 库,并使用 createApp 方法创建了一个 App 组件,然后通过 mount 方法挂载到页面上,这里的 App 组件就是通过模板字符串来定义的。这样就可以在 JS 代码中编写用户界面,是不是很方便呢?我们发现,在模板字符串中,我们使用 ${} 来引用数据,并且使用 onClick 方法来绑定事件。这样就可以实现一个计数器的功能。

除了这种简单的示例,Strve 还支持很多复杂的功能,我们可以使用 JSX 语法来编写组件,也可以使用函数式组件来编写组件,还可以使用组件来编写组件,甚至可以编写一些自定义的组件。

如果想了解更多关于 Strve 的信息,稍后可以到文章末尾处查阅官方文档。

性能评估

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

在评估之前,我们必须要了解 js-framework-benchmark 中有两种模式。一种是 keyed,另一种是 non-keyed。在 js-framework-benchmark 中,“keyed” 模式是指通过给数据项分配一个唯一标识符作为 “key” 属性,从而实现数据项与 DOM 节点之间的一对一关系。当数据发生变化时,与之相关联的 DOM 节点也会相应更新。而 non-keyed 模式是指当数据项发生变化时,可能会修改之前与其他数据项关联的 DOM 节点。

因为 Strve 支持keyed模式,所以我们将使用此模式来评估 Strve 的性能。

对以下操作进行了基准测试:

  • 创建行:页面加载后创建 1,000 行的持续时间(无预热)。
  • 替换所有行:替换表中所有 1,000 行的持续时间(5 次预热迭代)。
  • 部分更新:对于具有 10,000 行的表,每 10 行更新一次文本(进行 5 次预热迭代)。
  • 选择行:响应单击该行而突出显示该行的持续时间。 (5 次预热迭代)。
  • 交换行:在包含 1,000 行的表中交换 2 行的时间。 (5 次预热迭代)。
  • 删除行:删除具有 1,000 行的表的行的持续时间。 (5 次预热迭代)。
  • 创建多行:创建 10,000 行的持续时间(无预热)
  • 将行追加到大型表:在包含 10,000 行的表中添加 1,000 行的持续时间(无预热)。
  • 清除行:清除填充有 10,000 行的表的持续时间。 (无热身)
  • 就绪内存:页面加载后的内存使用情况。
  • 运行内存:添加 1,000 行后的内存使用情况。
  • 更新内存:1000 行的表点击 5 次更新后的内存使用情况。
  • 替换内存:点击 5 次创建 1000 行后的内存使用情况。
  • 重复清除内存:创建并清除 1,000 行 5 次后的内存使用情况。
  • 更新内存:1000 行的表点击 5 次更新后的内存使用情况。
  • 启动时间:加载和解析 javascript 代码以及渲染页面的持续时间。
  • 持续交互:灯塔指标 TimeToConstantlyInteractive:悲观 TTI - 当 CPU 和网络都非常空闲时。 (不再有超过 50 毫秒的 CPU 任务)
  • 脚本启动时间:灯塔指标 ScriptBootUpTtime:解析/编译/评估所有页面脚本所需的总毫秒数
  • 主线程工作成本:灯塔指标 MainThreadWorkCost:在主线程上工作所花费的总时间包括样式/布局等。
  • 总字节权重:灯塔指标 TotalByteWeight:加载到页面中的所有资源的网络传输成本(压缩后)。

对于所有基准测试,都会测量持续时间,包括渲染时间。

因为js-framework-benchmark是一个自动化测试的工具,只需要符合标准的代码就可以进行测试。Strve 支持 JSX 语法,所以我们将使用 JSX 语法来编写测试代码。

import { setData, createApp } from 'strve-js';
import { buildData } from './data.js';let selected;
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>{rows.map((item) => (<tr class={item.id === selected ? 'danger' : ''} data-label={item.label} key={item.id}><td class='col-md-1'>{item.id}</td><td class='col-md-4'><a onClick={() => select(item.id)}>{item.label}</a></td><td class='col-md-1'><a onClick={() => remove(item.id)}><span class='glyphicon glyphicon-remove' aria-hidden='true'></span></a></td><td class='col-md-6'></td></tr>))}</tbody>);
}function MainBody() {return (<fragment><div class='jumbotron'><div class='row'><div class='col-md-6'><h1>Strve-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'><buttontype='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'><buttontype='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'><buttontype='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></fragment>);
}createApp(() => MainBody()).mount('#main');

以下页面就是将进行基准测试的页面:

在这里插入图片描述
我们大体看下测试过程,我们将使用动图来展示页面效果,这样会觉得更加直观。

在这里插入图片描述

最终,Strve 通过了压力测试!

在这里插入图片描述

基准测试结果

既然我们通过测试,我们就需要提交到js-framework-benchmark官方项目中,进行综合评估,与全球其他框架进行比较。

我们提交的 PR 在 2023 年 9 月 18 号被作者合并了。

在这里插入图片描述

在接下来的时间里,作者进行了一系列的测试。最终,Chrome 118 版本于上周发布,并在 GitHub 上公布了官方的测试结果。

在这里插入图片描述

我们打开下面的网址,看下 Strve 的官方测试结果:

https://krausest.github.io/js-framework-benchmark/2023/table_chrome_118.0.5993.70.html

经过查询,全球 JavaScript 框架榜单中共有 142 个框架。

性能测试基准分为三类:

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

【持续时间】

在此测试基准中,Strve 平均值 1.42,排名第 90 位。

React、Angular 和 Vue,平均值分别为1.401.381.20,分别排名第 85 位、第 83 位和第 51 位。

平均值越小,排名则越靠前。颜色越绿代表越优。

在这里插入图片描述

【启动指标】

在此测试基准中,Strve 平均值 1.07

React、Angular 和 Vue,平均值分别为 1.681.801.30

平均值越小,排名则越靠前。颜色越绿代表越优。

在这里插入图片描述

【内存分配】

在此测试基准中,Strve 平均值 1.33

React、Angular 和 Vue,平均值分别为 2.462.821.86

平均值越小,排名则越靠前。颜色越绿代表越优。

在这里插入图片描述

新特性

我们在上面的测试中,可以看到 Strve 性能表现非常不错。

这次我们发布的大版本号为 6.0.2,我们将这个具有里程碑意义的大版本命名为 Strve6,而 “Strve6,从芯出发!” 这个口号正是 Strve6 的核心理念。这一版本象征着我们从底层技术出发,致力于为用户提供更优质、更高效的开发体验。

此次版本我们在性能与体验之间做了权衡。在源码层面,我们将普通 Diff 算法升级为 双端 Diff 算法,大大提升了性能。另外,我们在用户体验层面也做了很大的改进。

这里,我们提到了双端 Diff 算法,我们在面试中经常提到这个概念,但是很少用到实际项目中去。那么,为了更好地理解双端 Diff 算法如何提高性能,我们来看一个关于 Strve 简单的示例。

我们来遍历一个数组,并且每次点击按钮,往数组头部中添加一个元素。

【普通 Diff 算法】

<script type="module">import {html,setData,createApp,} from 'https://cdn.jsdelivr.net/npm/strve-js@6.0.2/dist/strve.full-esm.js';const state = {arr: [1, 2],count: 3,};function useUnshift() {setData(() => {state.count++;state.arr.unshift(state.count);});}function App() {return html`<fragment><button onClick=${useUnshift}>Unshift</button><ul>${state.arr.map((todo) => html`<li>${todo}</li>`)}</ul></fragment>`;}const app = createApp(App);app.mount('#app');
</script>

我们可以看到右侧 DOM 树,每次点击按钮,都会重新渲染整个列表。这样是肯定耗损浏览器性能的。

在这里插入图片描述

【双端 Diff 算法】

<script type="module">import {html,setData,createApp,} from 'https://cdn.jsdelivr.net/npm/strve-js@6.0.2/dist/strve.full-esm.js';const state = {arr: [1, 2],count: 3,};function useUnshift() {setData(() => {state.count++;state.arr.unshift(state.count);});}function App() {return html`<fragment><button onClick=${useUnshift}>Unshift</button><ul>${state.arr.map((todo) => html`<li key=${todo}>${todo}</li>`)}</ul></fragment>`;}const app = createApp(App);app.mount('#app');
</script>

我们可以看到右侧 DOM 树,每次点击按钮,仅添加必要的元素,而不是重新渲染整个列表。这是因为我们在每个列表项中添加了 key 属性,并且这个 key 是唯一的。key 这个特殊的 attribute 主要作为 Strve 的虚拟 DOM 算法提示,在比较新旧节点列表时用于识别 vnode。只要标签类型与 key 值都相等,就说明当前元素可以被复用。

在这里插入图片描述

热门话题

文章接近尾声,让我们来回顾一下最近社区的几个热门话题。

  1. 为什么要开发这个框架?初衷是什么?

答:其实,我的动机特别简单,完全受 JSX 语法的影响。刚接触 JSX 语法的时候,就被它那种魔法深深地吸引住了,可以在 JS 中写 HTML。所以,我就想我自己可不可以也搞一个类似 JSX 语法的库或者框架呢!一方面可以锻炼自己的代码能力,另一方面体验开发框架的整个流程,也方便我以后更全面的学习其他框架(Vue.js、React.js 等)。

做自己喜欢的事情是特别有意义的!

  1. 为什么选择 Strve 作为框架的名字?

答:Strve 最初定位是可以将字符串转换为视图(用户界面)的 JavaScript 库,所以是由 StringView 两个单词缩减组成的新单词。

  1. 跟前端热门框架比较,是想超过它们吗?

答:不是,我主要是想学习一下前端热门框架的实现原理,然后自己实现一个框架。有一句话说得好:“只有站在巨人的肩膀上才能望得更远!”。

  1. 记得之前也写过登上框架榜单的文章,这次为什么还要写?

答:之前,Strve 测评的模式是使用"non-keyed"。现在,Strve 新的版本支持"keyed"模式,所以,我重新写了一篇文章,来介绍 Strve 的新特性。

  1. Strve 6.0.2 版本发布,普通 Diff 算法升级为双端 Diff 算法,可以简单讲下双端 Diff 算法的概念吗?

答:双端 diff 算法就是头尾指针向中间移动,分别判断头尾节点是否可以复用,如果没有找到可复用的节点再去遍历查找对应节点的下标,然后移动。全部处理完之后要对剩下的节点进行批量的新增和删除。

  1. Strve 是个 JavaScript 库还是 JavaScript 框架?

答:首先,我们来看下框架与库有什么区别?库更多是一个封装好的特定的集合,提供给开发者使用,而且是特定于某一方面的集合(方法和函数),库没有控制权,控制权在使用者手中,在库中查询需要的功能在自己的应用中使用,我们可以从封装的角度理解库;框架顾名思义就是一套架构,会基于自身的特点向用户提供一套相当于叫完整的解决方案,而且控制权的在框架本身,使用者要找框架所规定的某种规范进行开发。Strve 可以是框架,因为 Strve 提供了路由、插件等生态工具;Strve 也可以是库, 因为 Strve 可以单独作为一个渲染库。

  1. Strve 你还要继续维护下去吗?

答:是的,我还会继续维护下去,因为我也想学习下去,也希望能帮助到更多前端开发者。

关于

Strve 我是从 2021 年下半年开始开发,到现在也快两年了。在这两年中,从一个之前只会 调用 API 的码农,到现在可以独立开发一个框架,让我收获了很多。学习了如何去分析一个框架的实现原理,也学习了如何去设计一个框架。

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

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

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

结语

感谢各位读者的阅读,希望本文能对你有所帮助,如果喜欢本文,欢迎点赞,欢迎关注!

最后,分享一段话给大家:

很多时候

不是有希望才去坚持

而是在坚持的过程中慢慢看到希望

我们都是在暗夜里赶路的人

纵使满身疲惫也不肯轻言放弃

愿你所坚持的东西

终有一天反过来拥抱你

这篇关于自研框架跻身全球 JS 框架榜单,排名紧随 React、Angular 之后!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/386837

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

css中的 vertical-align与line-height作用详解

《css中的vertical-align与line-height作用详解》:本文主要介绍了CSS中的`vertical-align`和`line-height`属性,包括它们的作用、适用元素、属性值、常见使用场景、常见问题及解决方案,详细内容请阅读本文,希望能对你有所帮助... 目录vertical-ali

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处