× {{alert.msg}} Never ask again
Receive New Tutorials
GET IT FREE

React vs AngularJS vs KnockoutJS: a Performance Comparison

– {{showDate(postTime)}}

This article will compare the performance of React JS vs Angular JS vs Knockout JS in three different browsers: Chrome, Firefox, and Safari.


I’ve recently written an article comparing React JS and Angular JS, and it’s been getting a fair bit of attention, so I figured I’d go one step further and show how well each of the two perform. I’ve also added in Knockout JS to the mix here just for comparison’s sake, and also some raw JavaScript DOM manipulation to give a base line as to how well things work across the board.

I’ve put together a quick page that allows you to see the rendering time difference between the three frameworks, plus the raw DOM manipulation. It’s what I’ve been using to figure out how long each framework takes to render large lists, as seen in the results table below. Take a look here.

Testing Methodology

This is by no means a scientific test as to how well each framework performs. That said, though, I tried to make it equal across all frameworks, so to that end, I’m going to walk through how I wrote each framework’s test below. Basically, I generate a list of 1000 items that get rendered into a ul tag, and then measure how long it takes by measuring dates before and after a render. The user is able to select an item in the list, too, so it’s not just a straight html render; there are events bound. It’s not a perfect test by any stretch, but it gets the point across.

Note: If you’re interested in this section at all, you’re going to need at least a passing understanding as to how to build something in each of the frameworks. Tutorials on React, Angular and Knockout are outside the scope of this article.

React JS

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

$("#run-react").on("click", function() {
    var built = new Class({ data: data, selected: null });

    var data = _buildData(),
    date = new Date();

    React.render(built, $("#react")[0]);
    $("#run-react").text((new Date() - date) + " ms");
});

So as a quick run down, when the user initiates a run, I build up a new list of 1000 items, make a note of the current time, render the React class, and then measure how long it took and write that time to the page. The class itself is straightforward, with a quick loop in the render function to push all of the created li tags into an array, and then rendering that array into a containing div. There’s an onClick binding set on the li to select it, too.

Angular JS

<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>
angular.module("test", []).controller("controller", function($scope) {
    $scope.run = function() {
        var data = _buildData(),
        date = new Date();

        $scope.selected = null;
        $scope.$$postDigest(function() {
            $("#run-angular").text((new Date() - date) + " ms");
        });

        $scope.data = data;
    };

    $scope.select = function(item) {
        $scope.selected = item.id;
    };
});

The whole performance page is marked as an Angular app, so building up the module is pretty straightforward. Of note here is the $$postDigest hook, which is an internal Angular construct. It allows us to specify a callback to fire after a digest cycle has completed.

Knockout JS

<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>
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);
        $("#run-knockout").text((new Date() - date) + " ms");
    }
}, $("#knockout")[0]);

Here, we’re using an anonymous template for the Knockout bindings. We set up a click, text and css binding for indicating which item is selected, and a foreach loop in the Knockout html to actually do the rendering.

Raw DOM Manipulation

I added raw DOM manipulation to give a baseline as to how to run the same test without any fancypants framework.

<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>
$("#run-raw").on("click", function() {
    document.getElementById("raw").innerHTML = "";
    var data = _buildData(),
        date = new Date(),
        template = $("#raw-template").html(),
        html = "";

    for (var i = 0; i < data.length; i++) {
        var render = template;
        render = render.replace("{{className}}", "");
        render = render.replace("{{label}}", data[i].label);
        html += render;
    }

    document.getElementById("raw").innerHTML = html;

    $("#raw").on("click", ".test-data span", function() {
        $("#raw .selected").removeClass("selected");
        $(this).addClass("selected");
    });

    $("#run-raw").text((new Date() - date) + " ms");
});

For the raw section, I’m grabbing the template from a script tag (marked with type text/html) and replace some key words wrapped in double curly braces with the appropriate text. Click events are hooked up via jquery.

Results

I ran all the tests in in Chrome 39.0.2171.95, Firefox 34.0.5 and Safari 7.0.2 by opening the test page and clicking the run button for each framework ten times. If you’re interested in the raw data, I’ve made it available here. There are some fancy charts below which show the results.

Analysis

On average, React is the fastest at rendering a list of 1000 items. It’s a surprising result, because I would have expected raw DOM manipulation to be the fastest, as there’s nothing too hook up and so on. There’s an interesting outlier in the Chrome test in that the second run of the React test takes a very long time to run: almost 600ms. It happens every time the second test is run in Chrome after a fresh reload and I’m not sure why. Raw DOM manipulation comes in second, which doesn’t surprise me, as it’s obviously much lighter than either Angular or Knockout, with nothing else to hook up or take care of behind the scenes. Angular comes in third, and Knockout comes in last. Knockout takes an especially long time in Firefox (~420ms). On a related note, Safari is the best browser across the board for all of the tested frameworks, but slowest for the raw test.

If performance is your primary motivation, React is a good choice for a framework, especially if you’re showing large amounts of data. I understand that this example is relatively contrived, as nobody in their right mind is going to be showing 1000 items all at once, but I feel it’s indicative as to which framework performs better as a whole.


Codementor Chris Harrington is a front end developer with seven years experience building performant web applications. He recently focused on React, AngularJS and Knockout JS. He is in the process of building Leaf, a performant application used as a tool to keep track of issues and tasks that need to be completed in a software development environment.

Chris HarringtonNeed Chris’s help? Book a 1-on-1 session!


or join us as an expert mentor!



Author
Chris Harrington
Chris Harrington
5.0
I'm a front end developer with seven years experience building performant web applications. I've recently focused on React, AngularJS and Knockout JS.
Hire the Author

Questions about this tutorial?  Get Live 1:1 help from React experts!
Yuriy Linnyk
Yuriy Linnyk
5.0
14+ years, Full-stack Javascript Developer. I enjoy explaining basics patiently, or move to advanced topics in my expertise anytime.
★ 50% OFF for beginners - read more... ☺︎ Web development is my life, since 2002. For over decade I'm excited to work on the full stack of web...
Hire this Expert
suresh atta
suresh atta
4.9
Sr Web and Java Developer by profession and your friend by nature.
Web&Java developer and loves to fix bugs. I believe in Karma and I believe in the below quote. REAL PROGRAMMER'S EYE IS A...
Hire this Expert

Or Become a Codementor!

Live 1:1 help from expert developers

Codementor is your live 1:1 expert mentor helping you in real time.

comments powered by Disqus
Codementor is your live 1:1 expert helping you in real time