add benchmarks page

This commit is contained in:
Leo Horie 2014-05-16 09:37:03 -04:00
parent e23f69fc4e
commit d677480f9b
21 changed files with 186 additions and 15 deletions

34
docs/benchmarks.md Normal file
View file

@ -0,0 +1,34 @@
## Benchmarks
These benchmarks were designed to measure Javascript running time. This is significant because the gzipped size of a framework can be misleading in terms of how much code actually runs on page loads. In my experience, page loads happen far more commonly than one would expect in single page applications: power users open multiple tabs, and mobile users are open and close the browser very frequently. And as far as templating engines go, the initial page load represents the worst case for the rendering algorithm since there are very little room for performance optimization tricks. It's arguably also [one of the most important metric when it comes to performance](http://blog.kissmetrics.com/loading-time/).
The numbers shown here are best-run results for all frameworks, except for Mithril's case, for which I'm taking the worst-run result. The numbers aren't statistically rigorous (e.g. I didn't bother to calculate standard deviation), but they should be enough to give a rough idea of what is faster than what.
Generally speaking, these tests are making a deliberate effort to be **biased in favor of other frameworks:** for example, I don't load "optional-but-usually-used-in-real-life" things like the router module for Angular, or Marionette in Backbone's case, and I load the entirety of Mithril. In addition, this test deliberately avoids triggering `requestAnimationFrame`-based performance optimizations for Mithril, since this optimization does not exist in many frameworks and [*severely* skews numbers in Mithril's favor](http://jsperf.com/angular-vs-knockout-vs-ember/308) in CPU-intensive situations like parallax sites. I'm also NOT using the [Mithril template compiler](compiling-templates.md), which would also skew the benchmark in Mithril's favor.
To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh (Lower is better).
<div class="row">
<div class="col(4,4,6)">
<h3>Loading</h3>
<table>
<tr><td><a href="comparisons/mithril.parsing.html">Mithril</a></td><td><span class="bar" style="background:#161;width:1%;"></span> 0.28ms</td></tr>
<tr><td><a href="comparisons/jquery.parsing.html">jQuery</a></td><td><span class="bar" style="background:#66c;width:26%;"></span> 13.11ms</td></tr>
<tr><td><a href="comparisons/backbone.parsing.html">Backbone</a></td><td><span class="bar" style="background:#33c;width:37%;"></span> 18.54ms</td></tr>
<tr><td><a href="comparisons/angular.parsing.html">Angular</a></td><td><span class="bar" style="background:#c33;width:14%;"></span> 7.49ms</td></tr>
<tr><td><a href="comparisons/react.parsing.html">React</a></td><td><span class="bar" style="background:#6af;width:50%;"></span> 24.99ms</td></tr>
</table>
</div>
<div class="col(8,8,12)">
<h3>Rendering</h3>
<table>
<tr><td><a href="comparisons/mithril.rendering.html">Mithril</a></td><td><span class="bar" style="background:#161;width:4%;"></span> 9.44ms (uncompiled)</td></tr>
<tr><td><a href="comparisons/jquery.rendering.html">jQuery</a></td><td><span class="bar" style="background:#66c;width:17%;"></span> 40.27ms</td></tr>
<tr><td><a href="comparisons/backbone.rendering.html">Backbone</a></td><td><span class="bar" style="background:#33c;width:10%;"></span> 23.05ms</td></tr>
<tr><td><a href="comparisons/angular.rendering.html">Angular</a></td><td><span class="bar" style="background:#c33;width:50%;"></span> 118.63ms</td></tr>
<tr><td><a href="comparisons/react.rendering.html">React</a></td><td><span class="bar" style="background:#6af;width:33%;"></span> 79.65ms</td></tr>
</table>
</div>
</div>
Feel free to implement versions of the tests above in other frameworks, if you wish. The code is very simple.

View file

@ -280,6 +280,27 @@ Hopefully by now, you're starting to see why Mithril encourages the usage of `m.
Mithril uses them in other interesting ways elsewhere.
As a side note, some readers have pointed out that we can refactor the `add` method like this:
```javascript
this.add = function() {
if (this.description()) {
this.list.push(new todo.Todo({description: this.description()}));
this.description("");
}
}.bind(this);
```
The difference is that `add` no longer takes an argument, and we call `.bind(this)` at the end to lock the scoping of `this` inside of the `add` method
Then we can make the `onclick` binding on the template much simpler:
```
m("button", {onclick: ctrl.add}, "Add")
```
The only reason I talked about partial application here was to make you aware of that technique, since it becomes useful when dealing with parameterized event handlers. In real life, given a choice, you should always pick the simplest idiom for your use case, as we just did here.
---
To implement flow control in Mithril views, we simply use Javascript:
@ -313,7 +334,7 @@ todo.view = function(ctrl) {
return m("html", [
m("body", [
m("input", {onchange: m.withAttr("value", ctrl.description), value: ctrl.description()}),
m("button", {onclick: ctrl.add.bind(ctrl, ctrl.description)}, "Add"),
m("button", {onclick: ctrl.add}, "Add"),
m("table", [
ctrl.list.map(function(task, index) {
return m("tr", [
@ -391,12 +412,12 @@ todo.controller = function() {
this.list = new todo.TodoList();
this.description = m.prop("");
this.add = function(description) {
if (description()) {
this.list.push(new todo.Todo({description: description()}));
this.add = function() {
if (this.description()) {
this.list.push(new todo.Todo({description: this.description()}));
this.description("");
}
};
}.bind(this);
};
//here's the view
@ -404,7 +425,7 @@ todo.view = function(ctrl) {
return m("html", [
m("body", [
m("input", {onchange: m.withAttr("value", ctrl.description), value: ctrl.description()}),
m("button", {onclick: ctrl.add.bind(ctrl, ctrl.description)}, "Add"),
m("button", {onclick: ctrl.add}, "Add"),
m("table", [
ctrl.list.map(function(task, index) {
return m("tr", [

View file

@ -38,6 +38,7 @@
<h2 id="misc">Misc</h2>
<ul>
<li><a href="comparison.html">Differences from Other MVC Frameworks</a></li>
<li><a href="benchmarks.html">Benchmarks</a></li>
<li><a href="practices.html">Good Practices</a></li>
<li><a href="tools.html">Useful Tools</a></li>
</ul>

View file

@ -149,7 +149,7 @@ m.module(document.getElementById("example"), app);
<section class="performance">
<div class="container">
<h2>Performance</h2>
<p>To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh. (Lower is better)</p>
<p>To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh (Lower is better). <a href="benchmarks.html">Read more</a></p>
<div class="row">
<div class="col(4,4,6)">
<h3>Loading</h3>