React vs. AngularJS vs. KnockoutJS: ein Leistungsvergleich

Dieser Artikel vergleicht die Leistung von React JS vs. Angular JS vs. Knockout JS in drei verschiedenen Browsern: Chrome, Firefox und Safari.


Ich habe kürzlich einen Artikel geschrieben, in dem React JS und Angular JS verglichen werden, und er hat ziemlich viel Aufmerksamkeit erregt, also dachte ich, ich gehe noch einen Schritt weiter und zeige, wie gut jeder der beiden funktioniert. Ich habe der Mischung hier auch Knockout JS hinzugefügt, nur zu Vergleichszwecken, und auch einige rohe JavaScript-DOM-Manipulationen, um eine Grundlinie dafür zu geben, wie gut die Dinge auf der ganzen Linie funktionieren.

Ich habe eine kurze Seite zusammengestellt, auf der Sie den Unterschied der Renderzeit zwischen den drei Frameworks sowie die rohe DOM-Manipulation sehen können. Es ist das, was ich verwendet habe, um herauszufinden, wie lange jedes Framework zum Rendern großer Listen benötigt, wie in der Ergebnistabelle unten zu sehen ist. Schau mal hier.

Testmethodik

Dies ist keineswegs ein wissenschaftlicher Test, wie gut die einzelnen Frameworks abschneiden. Allerdings habe ich versucht, es für alle Frameworks gleich zu machen, also werde ich zu diesem Zweck unten durchgehen, wie ich den Test jedes Frameworks geschrieben habe. Grundsätzlich generiere ich eine Liste mit 1000 Elementen, die in a gerendert werden ul Tag und messen Sie dann, wie lange es dauert, indem Sie die Daten vor und nach dem Rendern messen. Der Benutzer kann auch ein Element in der Liste auswählen, also ist es nicht nur ein reines HTML-Rendering; es sind ereignisse gebunden. Es ist keineswegs ein perfekter Test, aber er bringt es auf den Punkt.

Notiz: Wenn Sie überhaupt an diesem Abschnitt interessiert sind, benötigen Sie zumindest ein vorübergehendes Verständnis dafür, wie man in jedem der Frameworks etwas aufbaut. Tutorials zu React, Angular und Knockout gehen über den Rahmen dieses Artikels hinaus.

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

Wenn der Benutzer einen Lauf startet, baue ich als schnellen Ablauf eine neue Liste mit 1000 Elementen auf, notiere die aktuelle Zeit, rendere die React-Klasse und messe dann, wie lange es gedauert hat, und schreibe diese Zeit in die Seite. Die Klasse selbst ist unkompliziert, mit einer schnellen Schleife in der Renderfunktion, um alle erstellten zu pushen li -Tags in ein Array und rendern dieses Array dann in einen Container div. Dort ist ein onClick Bindungssatz auf der li auch auswählen.

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

Die gesamte Leistungsseite ist als Angular-App gekennzeichnet, sodass der Aufbau des Moduls ziemlich einfach ist. Bemerkenswert ist hier die $$postDigest Hook, ein internes Angular-Konstrukt. Es ermöglicht uns, einen Rückruf anzugeben, der ausgelöst wird, nachdem ein Digest-Zyklus abgeschlossen ist.

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

Hier verwenden wir eine anonyme Vorlage für die Knockout-Bindungen. Wir richten eine Klick-, Text- und CSS-Bindung ein, um anzuzeigen, welches Element ausgewählt ist, und a foreach Schleife in der Knockout-HTML, um das Rendering tatsächlich durchzuführen.

Rohe DOM-Manipulation

Ich habe eine rohe DOM-Manipulation hinzugefügt, um eine Grundlage dafür zu schaffen, wie derselbe Test ohne ein ausgefallenes Framework ausgeführt werden kann.

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

Für den Rohteil nehme ich die Vorlage aus a script Tag (gekennzeichnet mit type text/html) und ersetzen Sie einige Schlüsselwörter in doppelten geschweiften Klammern durch den entsprechenden Text. Click-Events werden über jquery angebunden.

Ergebnisse

Ich habe alle Tests in Chrome 39.0.2171.95, Firefox 34.0.5 und Safari 7.0.2 ausgeführt, indem ich die geöffnet habe Testseite und zehnmal auf die Schaltfläche „Ausführen“ für jedes Framework klicken. Wenn Sie an den Rohdaten interessiert sind, habe ich sie zur Verfügung gestellt hier. Es gibt einige ausgefallene Diagramme unten, die die Ergebnisse zeigen.

Chrom

Feuerfuchs

Safari

Analyse

Im Durchschnitt ist React am schnellsten beim Rendern einer Liste mit 1000 Elementen. Es ist ein überraschendes Ergebnis, denn ich hätte erwartet, dass die rohe DOM-Manipulation am schnellsten ist, da es nichts zu verbinden gibt und so weiter. Es gibt einen interessanten Ausreißer im Chrome-Test, da der zweite Durchlauf des React-Tests sehr lange dauert: fast 600 ms. Es passiert jedes Mal, wenn der zweite Test in Chrome nach einem Neuladen ausgeführt wird, und ich bin mir nicht sicher, warum. Rohe DOM-Manipulation kommt an zweiter Stelle, was mich nicht überrascht, da sie offensichtlich viel leichter ist als Angular oder Knockout, und nichts anderes hinter den Kulissen angeschlossen oder gepflegt werden muss. Angular belegt den dritten und Knockout den letzten Platz. Knockout dauert bei Firefox besonders lange (~420ms). In diesem Zusammenhang ist Safari der beste Browser für alle getesteten Frameworks, aber der langsamste für den Rohtest.

Wenn Leistung Ihre Hauptmotivation ist, ist React eine gute Wahl für ein Framework, insbesondere wenn Sie große Datenmengen anzeigen. Ich verstehe, dass dieses Beispiel relativ erfunden ist, da niemand, der bei klarem Verstand ist, 1000 Elemente auf einmal zeigen wird, aber ich denke, es ist ein Hinweis darauf, welches Framework insgesamt besser funktioniert.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *