React vs Raw dom manipulation (v4)

Revision 4 of this benchmark created by Rob on


Preparation HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<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>

<div id="raw"></div>

Setup

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

Test runner

Ready to run.

Testing in
TestOps/sec
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 data = _buildData();

React.render(new Class({
  data: data,
  selected: null
}), document.querySelector('#raw'));
ready
Optimized DOM Manipulation
 var fragment = document.createDocumentFragment(),
     $raw = document.querySelector('#raw'),
     parentRow = document.createElement('div'),
     testData = document.createElement('div'),
     data = _buildData();

   parentRow.className = 'row';
   testData.className = 'col-md-12 test-data';

   parentRow.appendChild(testData);
   fragment.appendChild(parentRow);

   var getSpan = function(container, row) {
     var span = document.createElement('span');
     span.textContent = row.label;

     return span;
   }.bind(null, testData);

   data.map(getSpan);

   $raw.appendChild(fragment);

   $raw.addEventListener('click', function(e) {
     if (e.currentTarget.className === 'span') {
       document.querySelector('.selected').className = '';
       e.currentTarget.className = 'selected';
     }
   });
ready
Original DOM Manipulation Code
var data = _buildData(),
    template = $("#raw-template").html(),
    html = "";

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

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

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.