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


prtyaa
prtyaa 2023-12-26 17:14:12 63278
分类专栏: 资讯

前言

终于实现了一个重要目标!我独立研发的 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-benchmark 。js-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'>
                <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>
    </fragment>
  );
}

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

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

 

 

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

 

 

基准测试结果

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

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

 

 

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

 

 

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

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

性能测试基准分为三类:

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

【持续时间】

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

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

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

 

 

【启动指标】

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

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

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

 

 

【内存分配】

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

React、Angular 和 Vue,平均值分别为 2.462.82 和 1.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 值都相等,就说明当前元素可以被复用。

 

动图封面

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=30905
赞同 0
评论 0 条
prtyaaL1
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1489
银河麒麟打印带有图像的文档时出错  1407
银河麒麟添加打印机时,出现“server-error-internal-error”  1197
统信操作系统各版本介绍  1118
统信桌面专业版【如何查询系统安装时间】  1116
统信桌面专业版【全盘安装UOS系统】介绍  1071
麒麟系统也能完整体验微信啦!  1029
统信【启动盘制作工具】使用介绍  674
统信桌面专业版【一个U盘做多个系统启动盘】的方法  618
信刻全自动档案蓝光光盘检测一体机  529
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!