AngularJS vs Facebook React Cage Match

Currently I am working on an enterprise application with an AngularJS frontend and Web API backend.  In parts of the application the page load time in unbearable.  This is especially noticeable on pages with Angular repeater directives with around 100 items or more (even in Chrome).  This lead me to look at how we could speed up these slow pages and I stumbled across Facebook React.

The following demo is well worth checking out if you haven’t heard of Facebook React:

Facebook React is built for speed. The rendering model takes a very different approach to other two way binding libraries such as AngularJS or Knockout. Traditionally two way binding libraries rebuilt every changed element in the DOM every time any element changes.  This can obviously lead to redundant work. Facebook react works in a different way.  It builds a virtual DOM in the background and computes the minimum set of operations needed to transform the virtual DOM based on the changes made. This means that there are no wasted operations. This is a bit like the concept that is used in a 3D games where objects that are completely hidden from vision are not drawn and then drawn over they are simply not drawn at all.

To test which is faster I have built a simple angular app that tests an Angular repeater against a react component. The app simply creates an array of x size and then binds that array to the Angular repeater or React component (depending which button you click) and times it.

To implement the app I started with the angular-seed project as it gives you an out of the box AngularJS app (complete with node web server).  For angular I am using a straight forward repeater bound to the array.  To time how long the binding takes in angular I am using a directive:

.directive('postRepeatDirective', ['$timeout',  function($timeout) {
	return {
		link: function(scope, element) {
			if (scope.$last){
				$timeout(function(){
					var end = new Date();
					$('#results').text("## Angular rendering list took: " + (end - scope.startTime) + " ms");
				});
			}
		}
	}
	}

This function checks for when the $last element is bound by the ngRepeat directive. When it is it assumes that all of the elements have been bound so it stops the timer. The start time is set when you click the button.

For Facebook React things are very similar. Except we are using a directive to do all of the work:

directive('reactRepeater', [function() {
    return {
      restrict: 'E',
      link: function(scope, element) {
        scope.$watch('reactArray', function(newVal, oldVal) {

          React.renderComponent(ReactResults({
            array: scope.reactArray
          }), document.getElementById('reactResults'), function(){

          	var end = new Date();
          	if (scope.reactArray.length > 0){
        		$('#results').text("## React rendering list took: " + (end - scope.startTime) + " ms");
        	}
          });
        }, true);

      }
    }
}])

We are using this directive to delegate the rendering to react. React has a method called renderComponent. It’s first argument is the component you want to render. We are rendering our ReactResults component and passing it the array. The second argument is the element where you want that component to render. The third argument is a callback that fires when React has finished rendering the component so this is where we can put our timing logic.

The React component looks like:

var ReactResults = React.createClass({
  render: function() {

   var results = [];
   for(var i=0; i<this.props.array.length; i++){
   	results.push(React.DOM.p({}, 'Hello'))
   }

    return React.DOM.div({}, results);
  }
});

The astute reader will have noticed that we are still using AngularJS to watch the array. Indeed we are and this will alter the results. The reason for this is that I wanted to test React in the context of using it just for the rendering inside an AngularJS app. React only provides rendering capabilities. As is stated on React’s site they are the V in View in the usual MV* para-dime. You still need a framework to combine with React to get all of the other goodness you normally want when building a rich web application.

Onto the results. The following data shows how long it took Angular and React to render ever increasing numbers of array elements.  The times are in milliseconds.

Elements Angular React
10 5.33 2.00
100 35.00 9.33
1,000 201.33 57.67
10,000 2,064.67 383.00

 

chart

 

As I tried to increase the number of elements further Angular started to crash my browser :(.  As you can see from the graph above Angular is on an exponential curve as the number of elements increase.

The data confirms what is promised by the React guys. That React is a lightning fast rendering framework. Remember it has been hampered in these tests as it was bootstrapped by Angular!  The test proves that due to the modular nature of Angular it is easy to swap out the rendering part with another rendering engine such as React. This means that if you have an existing Angular application and you want a performance increase then using React components inside directives is a good solution.

To reiterate again Angular does give you a nice structure to your code. So using it along with something like React gives you both an awesome framework for structuring large applications and a fast(er) rendering than you would out of the box with Angular.

The code used for these tests is all up in github so you can run them for yourselves.  You will need node and git installed . If you want to run the application yourself follow these instructions:

git clone git@github.com:kevholditch/AngularVsReact.git
cd AngularVsReact
npm install
node ./scripts/web-server.js

Now the app should be running. Access it by hitting http://localhost:3000/app/index.html. Give it a try. As always comments welcome. I would be keen to hear of your experiences with Angular and React.