Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

jopen 10年前

一个可以构建大型网络应用并令人难以置信快和强大但轻量级的客户端框架

Riot.js是一个客户端模型-视图-呈现(MVP)框架并且它非常轻量级甚至小于1kb.尽管他的大小令人难以置信,所有它能构建的有如下:一个模板引擎,路由,甚至是库和一个严格的并具有组织的MVP模式。当模型数据变化时视图也会自动更新。

Riot.js快而且简单-事实上,是完全不同的规模-而且用它的应用也很快简单。真的。

让我详细解释吧。

最快

Riot.js是目前存在的JavaScript模板引擎中速度最快的。它比Resig的“微模板”快5倍,比Underscore快7倍。

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

在你应用中的模板影响着渲染时间。模板快可以让你的应用快。在大型应用中影响是很大的,特别是在非Webkit浏览器中。上述在火狐中用100K重复的测试可在Hogan花费1300ms而在Riot中耗时30ms。请在不同的浏览器中做做测试可以得到更好的结果。

最轻

下面是Riot和其它流行的客户端框架文件大小比较:

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

很明显,Riot的是最小的,而且框架的大小会影响到以下几个方面:

  1. 容易学习。需要看更少的书和指导。这种不同点影响是巨大的:想想看3个API和300个API的区别。你需要更多的时间来构建应用。这基本上是给大团队用的。错误的决定会导致整个工程失败。
  2. 更少专有语法,更多是直接用JavaScript。用通用的编程技巧代替一些框架自己的规则是很重要的。
  3. 更少的问题。更不容易受到攻击和发现弱点。所有的错误都是用户产生的问题点。令人沮丧的是有时候你的应用失败很有可能是因为框架引起的。
  4. 易嵌入。在哪里用Riot.js都不会让人觉得多余。框架不能比应用本身的代码量大。
  5. 更快。根据Google的报告,每增加1kb的JavaScript,浏览器就多花费1ms的时间来解析(1)
  6. 更节约。对于Amazon.com,每增加100ms的加载JavaScript时间会让其税收增加1%(2)。在2012年,Amazon 1%的税收总共$610.9百万。

如果你的工具是其它消费应用而用的,那么其大小可能更加重要。

最强大

这是一个令人震惊的部分:一个仅有1Kb的程序库创建一个待办事项的MVC应用所需的代码量:

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

应用所需代码量的图片传达出了一个好框架的能力。一个框架的全部意义在于解决公共问题,这样用户就不必重新发明轮子。写尽量少的代码但能实现更多功能。

代码量的大小取决于多种因素,比如编程风格,所以老实说你的目标不应该是代码量小,而是简单。

简洁是Riot真正闪亮的地方。

MVP设计模式

Riot使用Model-View-Presenter (MVP)设计模式来组织代码,这样它能够更模块化、更具可测试性且易于理解。

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

正如在MVC(模型-视图-控制器)或MVVM(模型-视图-视图模型)模式里,其目的是从应用程序的视图中分离逻辑,但MVP更简单。让我们把它和MVC比较一下:

Riot.js — 1Kb 大小的 JavaScript 的 MVP 框架

MVC模式更复杂。许多箭头围成一个圈。控制器的角色不明确,这种模式可以以许多不同的方式解释。事实上,这是造成有太多该模式下客户端框架的根本原因。

MVP则相反,没有太多的解释空间,歧义少。每部分的作用是明确的。它适合大大大小小的工程,是单元测试的最佳模式。

让我们看一下MVP在Riot中是如何工作的。

Model

Riot的models定义了你的应用。 它是你的商业逻辑对外提供的一个深思熟虑后的API。一个完全隔离的、可在浏览器和服务器端(node.js)运行的可测试单元。下面是一个待办事项应用。

function Todo(store) {        var self = this,        items = [];        self.add = function(label) {        var item = { ... };        items.push(item);           // notify others        self.emit("add", item);     }        self.remove = function(id) {        delete items[id];        self.emit("remove", item);     }        // + other public methods ...          // Enable MVP pattern (this is the secret for everything)     $.observable(self);        // save state     self.on("add remove edit", function() {        store.put(items);     })     }

这个Model是一个传统的JavaScript对象(POJO),没有框架风格。在MVC的术语中,这是一个域模型而不仅仅是数据访问层。

你有权使用prototype对象或对象构造器{}。以上只是我个人使用的JavaScript风格。

当设计一个model时,保持思路明确很重要。你需要的最后一件事是用一个框架来聚焦你的应用逻辑。JavaScript本身就具有巨大的表现力。

observable

观察者是从你应用中分离模型的关键:

$.observable(object); 

当一些重要的事件发生后,上面的函数调用给定的对象并通知给其它对象。视图将会重新绘制或者API使用者也可以用监听改变事件来予以扩展。

观察者是将你的应用分离为可维护的组件的关键。它是一个典型的设计模式来将模型从视图中分离出来。

"构建大应用的秘籍就是永远不要一下子做成大应用。要将你的应用分割为小的模块"。Justin Meyer,JavaScriptMVC的作者
"如果将不同组件绑的太紧,可重用性将降低,而且很难在改变一些组件时而不影响其它的组件。"--Rebecca Murphey,jQuery Fundamentals作者

在客户端框架中一个好的事件库是分离各组件的很重要的特性。这就是Riot受关注的原因。

观察者可以对给定对象添加如下方法:

  • emit(event_name, args...)— 带有可选参数并能触发一个命名事件
  • on(event_name, fn)— 当一个特定事件发生时调用给定的函数
  • one(event_name, fn)— 当一个特定事件触发时调用给定函数一次,额外的事件将没有作用
  • off(event_name)— 停止监听指定的事件

Riot 事件是基于jQuery事件的,所以它有很强大的特性,如命名空间,一次可以监听多个事件。

最重要的不同是它没有事件对象,因为它在DOM之外就没有相关的事件了。你也能很优雅的发送和接收参数而不用数组来完成。

// 发送事件  obj.emit("my-event", "1st argument", "2nd arg", ... argN);     // 接收事件  obj.on("my-event", function(arg1, arg2, ... argN) {     });

观察者模式产生于1988年的Smlltalk语言,自从那时起它就被用来构建用户接口了。它是一个设计模式,而不是框架。事件和监听器的本质是被分离关注点的优良代码。这也应该是你理念的核心部分。

换句话说:

你不需要用框架来写一个模块级的客户端应用。

视图

视图就是你的应用中可见的那部分。譬如文本,图片,表格,按钮,链接等等,html代码和css样式文件。

Riot视图尽可能的轻。没有了那些视图中本不该有的条件语句,循环,或者数据绑定,自定义的属性或元素。就是你对所有网页设计师期望的那种视图。

只有"模版"——也就是html代码块能在运行的时候插到视图里面。这些模版包含那些可以用Riot模版驱动很快用数据替换的变量。

下面是一段 待处理的MVC入口:

<li id="{id}">     <div class="view">        <input class="toggle" type="checkbox">        <label>{name}</label>        <button class="destroy"/>     </div>     <input class="edit" value="{name}">  </li>

这种”不合逻辑的html“ 没有弱点或可测试的界面。 它通过了w3c校验器并且运行更快。

实际逻辑在presenter里面.

呈现器

呈现器监听视图上的事件(点击,滚动,按键,返回按钮等等)以及模型(添加,删除或修改的东西)上的事件,当模型更新后视图和模型都会相应的变化。这种"中间人"显示的定义了用户是怎么使用接口的行为。下面是备忘录应用:

$(function() {        / 1. 初始化 /        // 创建一个模型对象     var model = new Todo(),           // 抓出这个视图HTML root实例        root = $("#todo-list"),           // 单个备忘录 HTML 模板        template = $("#todo-tmpl").html(),          / 2. 监听用户事件 /        // 点击"清除完毕"     $("#clear-completed").click(function() {        todo.remove("completed");     })        //点击"切换所有"     $("#toggle-all").click(function() {        todo.toggle(filter);     })        // ...          / 3. 监听模型事件 /          // 一个删除入口     todo.on("remove", function(items) {        $.each(items, function() {           $(this.id).remove()        })        // 一个编辑入口     }).on("edit", function(item) {        var el = $(item.id);        el.removeClass("editing");        $("label, .edit", el).text(item.name).val(item.name);     })        // ...     })

在你的应用中能决定每一个不同呈现器的感觉非常自由。这是基于UI(边栏,账目,头位置...)上的规则或是基于功能(登陆,添加,创建,删除...)。

呈现器可以用jQuery来使用所有的用户接口逻辑。

jQuery

jQuery绝对是最好的操作DOM的工具,而且它也能很好的创建呈现器。jQuery API设计的很漂亮而且所有的库都非常有用。目前在56%的网站中都有它的身影,92%的网站中用的JavaScript库都被人熟知。Riot将凭借它们引以为豪。

说用jQuery可以让代码更糟的错误观点让人失望。没有什么可以超越真理。人们认为代码很乱是因为代码将模型和视图混合了。为了防止此事件发生,通过观察可以简单的分离模型代码和视图代码。你不需要框架的。

用jQuery构建MVP模式,你所需要做的就是用接口而已。

最糟糕的事情就是因为错误的原因而丢弃jQuery。它可是高水平的生产高雅和具有可读性代码的API。其表达式语法简明而且只需要很少的键盘输入。它拥有很大的社区、大量的文档以及它能在所有浏览器上工作。用jQuery可以让你感受到自由而不是害怕。

目前构建数据的框架是在HTML层次来减少混乱代码的。突然间onclick属性隐藏在后面了(我惊讶的看着你)。编程书这样告诉我们,要将事物分离开来,在web开发中的意思如下:

  1. JavaScript要在CSS之外
  2. CSS要在JavaScript之外
  3. JavaScript要在HTML之外
  4. HTML要在JavaScript之外

Riot是简洁的方法,它不会让你在HTML视图中参杂任何逻辑。

URL的返回按钮

另一个让人困惑的来源是返回按钮。按照一般的约定,你需要一个叫“路由器”的工具。

其实这是不对的。

点击返回按钮或者改变URL是一个你可以监听的全局窗口事件。它应该和按下一个键盘按键事件一样。目前的路由器是一个为很基础功能而产生的巨大解决方案。没有必要将工具和处理URL事件相分离,这就像没有必要将工具和处理按键事件分离一样。

上面的路由器产生了混淆是因为它不符合典型的MVC模式。在之前的网络时代,传统的MVC应用没有URL。

Riot只有一个$.route函数来处理应用的状态和返回按钮

// 点击导航元素  $("#filters a").click(function(e) {        // 跳过链接默认行为     e.preventDefault();        //改变URL哈希部分     $.route($(this).attr("href"));     })     //监听URL改变事件  $.route(function(hash) {     /*        待办事件列表处理:           1. 清除列表并添加新项        2. 高亮导航上激活的元素        3. 更新视图计数器     */  })

你只需要一个函数。我把它称作人们所期待的“路由”。它的作用如“url”或“go”。在url参数的基础上,你可以有一个或着多个URL监听器来完成其功能。

如果你的应用严重依靠不同哈希参数,你可能需要一个全面的路由器,但在大多数应用中是不需要的。

这就是Riot!

目前客户端框架都存在以下错误的假设:

  1. 存在一大块常见的问题
  2. MVC(或MVP)需要一个框架
  3. jQuery让代码更加混乱

所有这些陈述都是相当的错误。

目前的框架都会劝说大家相信错误的信条,即在没有易懂的、科学的分析下可以创建好的网站和非常精致的营销。为了解决假设的问题而会产生新的问题。很不幸,大量的通信在处理不相干的问题点。

Riot就是反对现状!

目前的应用可以更加的快、简单和小巧。它们可以让更少的人维护,需要更少的知识和出现更少的错误。


模型应该是普通的JavaScript,视图应该是普通的HTML。它们两都应该独立的发展而互不影响。框架没有必要负担开发和命令事情如何发展。

没有“Backbone的方式”、“Angular 方式”或是“Ember的方式”。框架一直都是经典的编程技巧。

Riot是对平凡的JavaScript和jQuery的一种宣言。

接下来呢?

之前的一个博客主题是有关Riot.js和无框架化的JavaScript。我想要用无框架结构来控制应用。事实上,只需要3个函数即可。

我的下一篇博客主题则更深层次的讨论了用Riot构建现代化的JavaScript应用。你可以学习到Riot怎么处理测试,持久化,应用辅助程序,资源分享,以及文件操作。

最后,官方的Riot.js即将出发行版,并且它有为浏览器和nod.js发布了文档和Moot论坛。关注我们的 非死book页面推ter公告

浏览源码

Riot.js
Riot的MVC备忘录
模板性能测试