
前言
时隔一年,我终于带着新的思考成果回来了。这段时间潜心于寻找前端开发中用户体验与性能的最佳平衡点,取得了突破性进展 ------ 全新 JavaScript 库 Mettle.js
正式亮相!
有人或许会问:"为什么不在 Strve.js
上优化,而选择从头开发?" 原因有二:第一,Strve.js
的核心定位(名字蕴含的 Str
)强调了其在 模板字符串中书写类 HTML 的开发模式。我们希望新库能突破这种语法层面的限制,拥抱更广阔的可能性(如 JSX)。第二,是时候进行一次彻底的重构与进化,以更好地实现我们的设计哲学(回归原生、轻量化)。因此,Mettle.js
应运而生。
那我为什么取"Mettle
"这个名字呢?在英语中,"Mettle" 这个词通常指一个人的勇气、毅力或决心,尤其是在面对挑战或困境时的表现。 对于一个 JavaScript 库来说,使用 "Mettle" 作为名字暗示着设计上强调高性能、可靠性和灵活性。
既然重新开发新的 JavaScript 库,那么定位必须要明确。我们提倡回归原生 JavaScript,尽量不创建特殊语法,尽量不改变 JavaScript 语义,并坚持用我们熟悉的语法来完成应用的开发。如果你是一位经验丰富的前端开发者,我相信你也会和我们一样遇到相同的问题。有的前端框架太重,创建一个组件的样板代码过多;有的不符合直觉,有闭包陷阱;有的有太多和社区割裂的自创语法,不能很好的和其它类库结合;有的有太多自己的主张,侵入性太严重;有的对 TypeScript 支持不友好等等。
如今,前端真的是太重了,学习一个框架就像学习一门新语言一样。我们相信,只使用普通的 JavaScript 一样可以编写出高质量、可维护、简单且容易扩展的代码。
启程
前端开发经历了几个关键阶段:在很早的时候,我们只需要写点原生 JS 就能实现很多功能,但是慢慢会发现使用原生 JS 有时会浏览器兼容性问题,还有繁琐复杂的 DOM 操作让我们特别头疼。jQuery 的出现迅速风靡全球,一个 $ 走天下,学会 jQuery 就等同于学会了前端。在这之后,前端的具体开发不再被 JavaScript 的兼容性问题所困扰。
在 2009 年 AngularJS 和 Node.js 的诞生,也宣告前端工业革命的到来。AngularJS 的诞生,引领了前端 MVVM 模式的潮流;Node.js 的诞生,让前端有了入侵后端的能力,也加速了前端工程化的诞生。现在前端三大框架 Angular、React、Vue 的发展主线,也就是从这里开始的。在前端 MVVM 模式下,不同框架的目标都是一致的,就是利用数据驱动页面,但是怎么处理数据的变化,各个框架走出了不同的路线。
在前端框架这么多的时代下,为什么还要重复造轮子,还要开发Mettle
呢?其实跟之前开发的Strve.js
动机一样。刚接触 React 的时候,在 JS 文件 中写 HTML 语法 觉得很奇妙,后来就觉得自己可不可以也搞一个库来锻炼下自己的能力呢!于是在业余时间自己通过各种摸索搞了一个迷你版 JSX,但是在数据驱动层面上遇到了一些问题,几天的辗转反侧,自己终于想明白了。我为什么先要做一个仿 React 的库呢?我能不能换一种方式来实现这种类 JSX 语法呢!我们知道 ES6 语法中有模板字符串,你可以在里面写 HTML 标签,并且在字符串中可以嵌入变量。找到了开发方向,我就开始搜索各种资料,正式进入开发库的过程。这个过程是非常痛苦的,但庆幸的是库的开发都是我一个人参与的,我可以按照我的想法去做,去完善它。
但是随着时间的推移,觉得自己的定位有点模糊,所以才有了上面说的想要重新开发一个 JavaScript 库。说是重新开发也不是什么都没有,严格来说我们是在Strve.js
进行了重构升级。
诞生
什么是 Mettle
?
Mettle
是一个用于构建用户界面的 JavaScript 库。
-
更容易上手: 只要你对 HTML、CSS 和 JavaScript 已经基本熟悉,就可以直接上手。
-
顺滑的用户体验: 可以使用 JSX 语法编写 Mettle,大大提升用户开发体验。
-
声明式渲染: 我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系,开发者可以更加专注于业务逻辑的开发,不需要过多地关心 DOM 操作的细节。
-
符合直觉: 使用熟悉的原生 JavaScript 语法,不改变 JavaScript 语义,回归原生 JavaScript 的纯净。
-
性能出色 : 采用了虚拟 DOM 的模式,虚拟 DOM 使用 diff 算法的方法来计算出真正需要更新的节点,最大限度地减少了 DOM 操作以及 DOM 操作带来的排版与重绘损耗,从而显著提高了性能。另外,具体性能表现如何?我们的 JavaScript 库已在全球知名的 js-framework-benchmark 测评中交出了一份惊艳答卷!(具体成绩见下文性能部分)
-
组件化: 一个函数就是一个组件,可以根据应用规模任意组合。并且组件特有的 "孤岛特性(指组件的状态更新和虚拟 DOM 计算严格限制在其自身作用域内,不会波及其他组)",使得将虚拟 DOM 树计算的级别控制在组件级别。
-
灵活的应用场景: 有无构建工具都可以使用,并且可以适配到其他前端框架开发的应用项目中去。
体验
我们先来看下这段Mettle
代码,很简单的一个计数器的例子。
jsx
function App({ setData }) {
let count = 0;
function add() {
count++;
setData();
}
return () => <h1 onClick={add}>{count}</h1>
}
了解过 React 的小伙伴,看到上面的代码应该很熟悉,这不是纯函数组件嘛,但是又好像不是。我们看到有一个count
变量,一个add
函数,执行add
函数就会累加count
,这些都是原生 JS 语法。setData()
是 Mettle 提供的核心方法,用于通知框架数据已变更,触发视图更新。
这个例子清晰地展示了Mettle
的核心体验: 使用你熟悉的原生 JavaScript 语法(变量、函数),搭配直观的 JSX 来描述视图,仅需一个简单的setData()
调用来触发更新。 我们认为这就是理想中的开发方式 ------ 贴近原生,简洁高效。
我也是一名前端开发者,感觉前端真的是太重了,每学习一个框架就像学习一门新语言一样,需要记各种语法。Mettle
要完成的就是尽可能的提升开发体验,让开发像行云流水一般流畅。
性能
一个库的性能也是非常重要的,自己怎么夸都是没有证据的。所以,我们打算通过 js-framework-benchmark
这个项目来评估下性能。
js-framework-benchmark
是什么?我们这里就简单介绍下,它是一个用于比较 JavaScript 框架性能的项目。它旨在通过执行一系列基准测试来评估不同框架在各种场景下的性能表现。这些基准测试包括渲染大量数据、更新数据、处理复杂的 UI 组件等。通过运行这些基准测试,可以比较不同框架在各种方面的性能优劣,并帮助开发人员选择最适合其需求的框架。js-framework-benchmark
项目提供了一个包含多个流行 JavaScript 框架的基准测试套件。这些框架包括 Angular、React、Vue.js、Ember.js 等。每个框架都会在相同的测试场景下运行,然后记录下执行时间和内存使用情况等性能指标。通过比较这些指标,可以得出不同框架的性能差异。这个项目的目标是帮助开发人员了解不同 JavaScript 框架的性能特点,以便在选择框架时能够做出更加明智的决策。同时,它也可以促进框架开发者之间的竞争,推动框架的不断改进和优化。
测试标准包括:
-
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。
下面这张图是我本地使用js-framework-benchmark
测试了下,性能跟内存占用都是挺好的,也达到了我的预期。

但是,为了能够跟其他框架进行一较高下,我决定还是发布到榜单上,在统一的运行环境下进行测评更有价值。
于是,我就提了 PR。

上面的图就是跑分结果,因为是跟 Vue@3.6
一块提交的 PR,所以会放在一起比较,黑框框起来的就是分数,分数越低,排名越靠前。Vue@3.6
分数1.27
,而Mettle@1.1.2
分数1.30
,仅仅相差0.3
分。这比分确实让我出乎意料,为了可以看更详细的数据,我打开总测评榜单。
krausest.github.io/js-framewor...
我挑选了这几个比较知名的框架或者库进行比较。分别是vue
、react
、preact
、vue-jsx
、angular
。

在这么多大佬框架面前,综合比分仅次于vue
。另外其他指标,比如内存分配和首次绘制比分都是排名靠前。

这是多么有成就感的一件事,自己开发的 JavaScript 库居然能够在全球知名 JavaScript 库性能测评榜单中可以取得这么好的成绩。
从上面这么多数据可以看出Mettle
在性能方面可以抗打!
意义
js-framework-benchmark
的测试结果是相对准确的,因为它是针对同样的测试样本和基准测试情境进行比较,可以提供框架之间的相对性能比较。然而,需要注意的是,这个测试结果也只是反映了测试条件下的性能表现。框架实际的性能可能还会受到很多方面的影响。 此外,js-framework-benchmark
测试结果也不应该成为选择框架的唯一指标。在选择框架时,还需要考虑框架的生态、开发效率、易用性等多方面因素,而不仅仅是性能表现。
虽然 Mettle 是一个非常新的库,在成熟度和生态上暂时无法与巨头们相提并论,但我们欣慰地看到,在js-framework-benchmark
这一严格考验框架效率的权威测评中,Mettle 的核心性能指标已展现出显著竞争力。与诸多前辈同台竞技并获得亮眼分数,这充分证明了其底层设计与实现的高效性。
我们深知,是开源生态和无数优秀前辈的工作奠定了创新的基石。Mettle
从这些杰出项目中汲取养分,并致力于在前端性能优化与开发体验纯净性上贡献自己的解决方案。我们相信,良性的对比与竞争,正是推动整个前端生态不断前行的核心动力之一。
Mettle
要走的路还有很长,入选榜单使我更加明确了方向。我觉得做自己喜欢做得事情,这样才会有意义!
展望
Mettle
要继续维护下去,我也会不断学习,继续精进。Mettle
还有很多值得探索的特性,我就不在文章中赘述了,可以点击下面的文档链接。
中文文档 :maomincoding.github.io/mettle-doc/...
Github :github.com/maomincodin...
感谢您的阅读!如果您对 Mettle
的理念或表现感兴趣,欢迎在 GitHub 上 给予一个 Star 支持 。您的每一个 Star,都是我们持续优化和建设的强大动力!
后续我们计划在开发者工具集成、性能体验、SSR 等方面持续发力!