加载中

An incredibly fast, powerful yet tiny client side framework for building large scale web applications.

Riot.js is a client-side Model-View-Presenter (MVP) framework that weighs less than 1kb. Despite the unbelievable size, all the building blocks are there: a template engine, router, event library and a strict MVP pattern to keep things organized. Your views are automatically updated when the underlying model changes.

Riot.js is faster and simpler — in fact, on a completely different scale — and applications built with it are also faster and simpler. For real.

Let's go deeper.

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

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

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

让我详细解释吧。

Fastest

Riot.js comes with the fastest JavaScript templating engine that currently exists. It's ~5 times faster than Resig's "micro templating" or ~7 times faster than Underscore.

Templating affects the rendering time of your application. Faster templating makes for a faster app. On bigger applications the difference can be huge, especially on non- Webkit browsers. The above test can take 1300ms in Hogan and 30ms in Riot with 100k repeats on Firefox. Please try the above test with different browsers to get a better picture.

最快

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

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

Smallest

Here is how Riot stack up to some of the popular client-side frameworks.

Riot is the smallest by a clear margin, and the size of a framework does matter:

  1. Less to learn. Fewer books and tutorials to view. The difference here is enormous: think 3 API methods instead of 300. You'll spend more time building the actual application. Essential for bigger teams. Projects can fail due to wrong decisions.

  2. Less proprietary idioms, more straightforward JavaScript. It's way more important to master universal programming skills instead of some framework's own, opinionated rules.

  3. Less bugs. Less vulnerable surface and weak spots. All bugs should be user bugs. It's frustrating when your application fails because of a bug on the framework.

  4. Embeddable. Use Riot.js everywhere without additional bloat. Framework should not be bigger than the application itself.

  5. Faster. According to Google, each kilobyte of JavaScript adds 1ms of parse time to the overall page load time (1).

  6. Cheaper. Amazon.com increased its revenue by 1% for every 100 milliseconds of load time improvement (2). In 2012, 1% of Amazon’s revenues amounted to $610.9 Million

If you are building a tool for others' consumption, size is even more important.

最轻

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

很明显,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百万。

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

Most powerful

Here's the shocking part: a 1Kb library requires the least keystrokes to build the Todo MVC application:

The size of the required application code gives a good picture of the capabilities of a framework. The whole purpose of a framework is to solve common problems so users won't have to reinvent the wheel. Write less, achieve more.

The size of the code obviously depends on multiple factors such as the programming style, so honestly your goal should not be small, but simple.

And simplicity is where Riot really shines.

最强大

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

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

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

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

MVP design pattern

Riot uses Model-View-Presenter (MVP) design pattern to organize your code so that it's modular, testable and easy to understand.

Model View Presenter

Just like in MVC (Model View Controller) or MVVM (Model View ViewModel), the purpose is to separate your application logic from the view, but MVP is simpler. Let's take MVC for comparison:

Model View Controller

MVC is more complex. The many arrows form a circle. The role of the controller is not clear, and the pattern can be interpreted in many different ways. In fact, this is the root cause for the explosion of client-side frameworks.

MVP, on the other hand, has less room for interpretation. The role of each part is clear. It works for big and small projects, and is the best pattern for unit tests.

Let's see how MVP works in Riot.

MVP设计模式

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

Model View Presenter

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

Model View Controller

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

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

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

Model

Riot models define your application. It's your business logic exposed to outer world with a well-thought API. A completely isolated, testable unit that can be run in browser and server (node.js). Here is one for the Todo app.

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);
   })
 
}

The Model is a plain old JavaScript object (POJO) without framework specific idioms. In MVC terminology it's a domain model  rather than just a data access layer.

You have the freedom to build your models in your preferred way using theprototypeobject or the object constructor{}. The above is just my personal style of writing JavaScript.

When designing a model it's important to clean your mind. The last thing you want is a framework to steal your focus. It's your precious business logic! JavaScript has tremendous expressive power in itself.

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本身就具有巨大的表现力。

The observable

Observables are they key for separating the model from the rest of your application:

$.observable(object); 

After the above call the given object is able to notify others when something crucial happens. The views can re-render themselves or the users of the API users can make their extensions by listening to the changes.

Observables are the key to splitting your app into maintainable components. It's a classic design pattern to separate the Model from the View.

"The secret to building large apps is never build large apps. Break your applications into small pieces" — Justin Meyer, author of JavaScriptMVC

"The more tied components are to each other, the less reusable they will be, and the more difficult it becomes to make changes to one without accidentally affecting another" — Rebecca Murphey, author of jQuery Fundamentals

A good event library is the single most important feature in a client-side framework. And this is where Riot places the biggest focus.

observable

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

$.observable(object); 

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

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

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

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

The observable call adds following methods to the given object:

  • emit(event_name, args...)— trigger a named event with optional arguments
  • on(event_name, fn)— call the given function when a particular event is triggered
  • one(event_name, fn)— call the given function once when a particular event is triggered. additional events cause no action
  • off(event_name)— stop listening to a specified event

Riot events are based on jQuery events, so all the powerful features are there, such as namespaces , and the ability to listen to multiple events at once.

The most important difference is that there is noEvent object because it's not relevant outside the DOM. You can also send and receive arguments nicely without wrapping them to an array:

// send event
obj.emit("my-event", "1st argument", "2nd arg", ... argN);
 
// receive event
obj.on("my-event", function(arg1, arg2, ... argN) {
 
});
Observables were introduced in 1988 by Smalltalk and have been used to build user interfaces ever since. It's a design pattern, not a framework. Events and listeners are the essence of good code with separated concerns. They should be a core part of your mindset.

Let me put this in another way:

You don't need a framework to write modular client-side applications.

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

  • 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语言,自从那时起它就被用来构建用户接口了。它是一个设计模式,而不是框架。事件和监听器的本质是被分离关注点的优良代码。这也应该是你理念的核心部分。

换句话说:

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

View

View is the visible part of your application. Text, images, tables, buttons, links and the like. The HTML and the CSS.

Riot views are as dummy as possible. No conditional statements, loops, or data binding. No custom attributes or custom elements. These should be absent from the view. Views are something you can expect from any HTML developer.

There are only "templates" — fragments of HTML that can be inserted in the view at runtime. These templates contain variables that are substituted with data using the extremely fast Riot template engine.

Here's one for a single TodoMVC entry:

<li id="{id}">
   <div class="view">
      <input class="toggle" type="checkbox">
      <label>{name}</label>
      <button class="destroy"/>
   </div>
   <input class="edit" value="{name}">
</li>
This kind of "logicless HTML" has no weak spots or testable surface. It's faster and passes W3C validator.

The actual logic is inside the presenter.

视图

视图就是你的应用中可见的那部分。譬如文本,图片,表格,按钮,链接等等,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里面.

Presenter

Presenter listens to what happens on the View (click, scroll, keyboard, back button etc) and on the Model (things are added, removed or modified) and it updates both view and model accordingly. This "middleman" explicitly defines how the user interface behaves. Here's one for the Todo app:

$(function() {
 
   / 1. Initialize /
 
   // create a model instance
   var model = new Todo(),
 
      // Grab the HTML root of this view
      root = $("#todo-list"),
 
      // HTML template for a single todo- entty
      template = $("#todo-tmpl").html(),
 

   / 2. Listen to user events /
 
   // "clear completed" is clicked
   $("#clear-completed").click(function() {
      todo.remove("completed");
   })
 
   // "toggle all" is clicked
   $("#toggle-all").click(function() {
      todo.toggle(filter);
   })
 
   // ...
 

   / 3. Listen to model events /
 

   // an entry was removed
   todo.on("remove", function(items) {
      $.each(items, function() {
         $(this.id).remove()
      })
 
   // an entry was edited
   }).on("edit", function(item) {
      var el = $(item.id);
      el.removeClass("editing");
      $("label, .edit", el).text(item.name).val(item.name);
   })
 
   // ...
 
})
I have put all the logic inside a single presenter, but there can be multiple presenters performing a separate task. For example, I could have put all the logic for a single todo entry in a separate file.

Feel free to decide the role of each presenter that makes the most sense for your application. This can be based on the role on the UI (sidebar, account, header...) or based on functionality (login, join, create, remove...).

Presenter has all the user interface logic, expressed with jQuery.

呈现器

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

$(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来使用所有的用户接口逻辑。

返回顶部
顶部