Backbone Events vs. Ember Bindings: A Benchmark

Animating 100 (or N) circles with your standard Backbone events and Ember bindings.

by blesh

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="//underscorejs.org/underscore-min.js"></script>
<h2>Using the strange "benchmarkLoop" method of measurement from the other tests</h2>

<div ng-app="animateApp">
    <div id="grid" ng-controller="MainCtrl">
        <p id="timing"></p>
        <div class="box-view" ng-repeat="item in items track by $index">
            <div class="box" id="box-{{$index}}" ng-style="{
        top: item.top + 'px',
        left: item.left + 'px',
        background: 'rgb(0,0,' + item.color + ')'
        }">{{item.content}}</div>
        </div>
    </div>
</div>

CSS

p {
    font: 12px/16px Arial;
    margin: 10px 10px 15px;
}
button {
    font: bold 14px/14px Arial;
    margin-left: 10px;
}
#grid {
    margin: 10px;
}
.box-view {
    width: 20px;
    height: 20px;
    float: left;
    position: relative;
    margin: 8px;
}
.box {
    border-radius: 100px;
    width: 20px;
    height: 10px;
    padding: 5px 0;
    color: #fff;
    font: 10px/10px Arial;
    text-align: center;
    position: absolute;
}

JavaScript

// Change N to change the number of drawn circles.

var N = 100;

var app = angular.module('animateApp', []);

app.controller('MainCtrl', function ($scope, $timeout, $window) {
    var Math = $window.Math,
        i,
        count = 0;

    $scope.items = [];
    for (i = 0; i < N; i++) {
        $scope.items.push({});
    }

    $scope.totalTime = 0;

    var animate = function () {
        $scope.$apply(function () {
            angular.forEach($scope.items, function (item) {
                item.top = Math.sin(count / 10) * 10;
                item.left = Math.cos(count / 10) * 10;
                item.color = (count) % 255;
                item.content = count % 100;
                count++;
            });
        });
    };

    // defer the animate call until after the controller
    // as been created, so we don't get a duplicate $apply error.
    _.defer(function () {
        window.benchmarkLoop(animate);
    });
});

var totalTime = 0,
    loopCount = 0;

window.benchmarkLoop = function(fn) {
    var startDate = new Date();
    fn();
    var endDate = new Date();
    totalTime += endDate - startDate;
    loopCount++;
    if (loopCount % 20 === 0) {
        angular.element('#timing').text('Performed ' + loopCount + ' iterations in ' + totalTime + ' ms (average ' + (totalTime / loopCount).toFixed(2) + ' ms per loop).');
    }
    timeout = _.defer(benchmarkLoop, fn);
};