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.
+
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 in CPU-intensive situations like parallax sites. I'm also NOT using the Mithril template compiler, 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).
Note that when we construct the parameterized binding, we are passing the description getter-setter by reference, and not its value. We only evaluate the getter-setter to get its value in the controller method. This is a form of lazy evaluation: it allows us to say "use this value later, when the event handler gets called".
Hopefully by now, you're starting to see why Mithril encourages the usage of m.prop: Because Mithril getter-setters are functions, they naturally compose well with functional programming tools, and allow for some very powerful idioms. In this case, we're using them in a way that resembles C pointers.
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:
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:
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)
+
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). Read more
diff --git a/docs/benchmarks.md b/docs/benchmarks.md
new file mode 100644
index 00000000..a992aef8
--- /dev/null
+++ b/docs/benchmarks.md
@@ -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).
+
+
+
+Feel free to implement versions of the tests above in other frameworks, if you wish. The code is very simple.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index e02a4d97..1f11a1ea 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -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", [
diff --git a/docs/layout/guide.html b/docs/layout/guide.html
index 16c7015b..d9742e73 100644
--- a/docs/layout/guide.html
+++ b/docs/layout/guide.html
@@ -38,6 +38,7 @@
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)
+
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). Read more