Skip to content

Instantly share code, notes, and snippets.

@RichAyotte
Last active January 10, 2019 22:52
Show Gist options
  • Save RichAyotte/a7b8780341d5e75beca7 to your computer and use it in GitHub Desktop.
Save RichAyotte/a7b8780341d5e75beca7 to your computer and use it in GitHub Desktop.
Performance Comparison for React, Angular and Knockout
<!DOCTYPE html>
<html ng-app="test">
<head>
<title>Performance Comparison for Knockout, Angular and React</title>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.css" rel="stylesheet" />
<style type="text/css">
* { box-sizing:border-box; }
body { padding:30px 0; }
h2 { margin:0; margin-bottom:25px; }
h3 { margin:0; padding:0; margin-bottom:12px; }
.test-data { margin-bottom:3px; }
.test-data span { padding:3px 10px; background:#EEE; width:100%; float:left; cursor:pointer; }
.test-data span:hover { background:#DDD; }
.test-data span.selected { background:#3F7AD9; color:white; }
.time { font-weight:bold; height:26px; line-height:26px; vertical-align:middle; display:inline-block; cursor:pointer; text-decoration:underline; }
</style>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react.js"></script>
<script type="text/javascript">
console.timeEnd("build");
document.addEventListener("DOMContentLoaded", function() {
_knockout();
_react();
_raw();
});
_angular();
function _buildData(count) {
count = count || 1000;
var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
var data = [];
for (var i = 0; i < count; i++)
data.push({id: i+1, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] });
return data;
}
function _random(max) {
return Math.round(Math.random()*1000)%max;
}
function _knockout() {
ko.applyBindings({
selected: ko.observable(),
data: ko.observableArray(),
select: function(item) {
this.selected(item.id);
},
run: function() {
var data = _buildData(),
date = new Date();
this.selected(null);
this.data(data);
document.getElementById("run-knockout").innerHTML = (new Date() - date) + " ms";
}
}, document.getElementById("knockout"));
}
function _angular(data) {
angular.module("test", []).controller("controller", function($scope) {
$scope.run = function() {
var data = _buildData(),
date = new Date();
$scope.selected = null;
$scope.$$postDigest(function() {
document.getElementById("run-angular").innerHTML = (new Date() - date) + " ms";
});
$scope.data = data;
};
$scope.select = function(item) {
$scope.selected = item.id;
};
});
}
function _react() {
var Class = React.createClass({
select: function(data) {
this.props.selected = data.id;
this.forceUpdate();
},
render: function() {
var items = [];
for (var i = 0; i < this.props.data.length; i++) {
items.push(React.createElement("div", { className: "row" },
React.createElement("div", { className: "col-md-12 test-data" },
React.createElement("span", { className: this.props.selected === this.props.data[i].id ? "selected" : "", onClick: this.select.bind(null, this.props.data[i]) }, this.props.data[i].label)
)
));
}
return React.createElement("div", null, items);
}
});
var runReact = document.getElementById("run-react");
runReact.addEventListener("click", function() {
var data = _buildData(),
date = new Date();
React.render(new Class({ data: data, selected: null }), document.getElementById("react"));
runReact.innerHTML = (new Date() - date) + " ms";
});
}
function _raw() {
var container = document.getElementById('raw')
, docFragment = document.createDocumentFragment()
, runRawNode = document.getElementById('run-raw')
, handler = function() {
var selected = container.querySelector('.selected');
if (selected) {
selected.className = '';
}
this.className = 'selected';
}
;
runRawNode.addEventListener("click", function() {
var data = _buildData()
, date = new Date()
if (!container.hasChildNodes()) {
var containerWrap = document.createElement('div');
container.appendChild(containerWrap);
for (var i = 0; i < data.length; i++) {
var div1 = document.createElement('div')
, div2 = document.createElement('div')
, span = document.createElement('span')
;
div1.className = 'row';
div2.className = 'col-md-12 test-data';
span.addEventListener('click', handler);
span.textContent = data[i].label;
div2.appendChild(span);
div1.appendChild(div2);
docFragment.appendChild(div1);
}
containerWrap.appendChild(docFragment);
container.appendChild(containerWrap);
} else {
for (var i = 0; i < data.length; i++) {
container.firstChild.childNodes[i].firstChild.firstChild.className = '';
container.firstChild.childNodes[i].firstChild.firstChild.textContent = data[i].label;
}
}
runRawNode.textContent = (new Date() - date) + " ms";
});
}
ko.observableArray.fn.reset = function(values) {
var array = this();
this.valueWillMutate();
ko.utils.arrayPushAll(array, values);
this.valueHasMutated();
};
</script>
</head>
<body ng-controller="controller">
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Performance Comparison for React, Angular and Knockout</h2>
</div>
</div>
<div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>React</h3>
</div>
<div class="col-md-5 text-right time" id="run-react">Run</div>
</div>
<div id="react"></div>
</div>
<div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Angular</h3>
</div>
<div class="col-md-5 text-right time" id="run-angular" ng-click="run()">Run</div>
</div>
<div>
<div class="row" ng-repeat="item in data">
<div class="col-md-12 test-data">
<span ng-class="{ selected: item.id === $parent.selected }" ng-click="select(item)">{{item.label}}</span>
</div>
</div>
</div>
</div>
<div id="knockout" class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Knockout</h3>
</div>
<div class="col-md-5 text-right time" id="run-knockout" data-bind="click: run">Run</div>
</div>
<div data-bind="foreach: data">
<div class="row">
<div class="col-md-12 test-data">
<span data-bind="click: $root.select.bind($root, $data), text: $data.label, css: { selected: $data.id === $root.selected() }"></span>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Raw</h3>
</div>
<div class="col-md-5 text-right time" id="run-raw">Run</div>
</div>
<div id="raw"></div>
</div>
</div>
<script type="text/html" id="raw-template">
<div class="row">
<div class="col-md-12 test-data">
<span class="{{className}}">{{label}}</span>
</div>
</div>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment