55

I was doing a comparison of Angular and React and decided to try out a performance test to see how fast a large(ish) list would render in both frameworks.

When I got done with my React prototype with some basic currency formating, it was taking ~2 seconds to render on my fast laptop. With Angular it was barely noticeable -- only when I switched to my phone did it have a noticeable lag.

This was very surprising because I was told that React was supposed to beat the pants off of Angular for performance, but it appears that the opposite is true in this case.

I distilled my prototype down to a very simple app to try to isolate the issue: https://github.com/pselden/react-render-test

In this sample, it's taking almost 200ms to render this simple list after changing the language, and I'm barely doing anything.

Am I doing something wrong here?

/** @jsx React.DOM */
'use strict';

var React = require('react'),
    Numbers = require('./Numbers');

var numbers = []
for(var i = 0; i < 2000; ++i){
    numbers.push(i);
}

var App = React.createClass({
    getInitialState: function() {
        return { locale: 'en-US' };
    },

    _onChangeLocale: function(event) {
        this.setState({locale: event.target.value});
    },

    render: function() {
        var currentLocale = this.state.locale;

        return (
            <div>
                <select
                    onChange={this._onChangeLocale}>
                    <option value="en-US">English</option>
                    <option value="fr-FR">French</option>
                </select>
                <Numbers numbers={numbers} locales={[currentLocale]} />
            </div>
        );
    }
});

module.exports = App;
/** @jsx React.DOM */
'use strict';

var React = require('react'),
    ReactIntlMixin = require('react-intl');

var Numbers = React.createClass({
    mixins: [ReactIntlMixin],

    getInitialState: function() {
        return {
            numbers: this.props.numbers
        };
    },

    render: function() {
        var self = this;
        var list = this.state.numbers.map(function(number){
            return <li key={number}>{number} - {self.formatNumber(number, {style: 'currency', currency: 'USD'})}</li>
        });

        return <ul>{list}</ul>;
    }
});

module.exports = Numbers;

PS: Added an angular version: https://github.com/pselden/angular-render-test

Edit: I opened an issue with react-intl and we investigated and found that there was not that much overhead with using https://github.com/yahoo/react-intl/issues/27 -- it's simply React itself that is slower here.

Paul
  • 4,422
  • 5
  • 29
  • 55

6 Answers6

48

This is definitely an interesting test case.

If you take a look at the timelines, you can see that Angular is finished handling the change event in a mere 20ms. The remainder of the time is spent in layout and repaint.

Angular Timeline

React (using a production build, your repo uses dev by default) takes about 59ms. Again, the rest of the time is spent in layout and repaint.

React Timeline

If you take a look at the CPU flame charts, you can see that Angular appears to be doing a lot less work.

Angular:

Angular CPU Graph

React:

React CPU Graph

React provides a pretty good optimization hook in the form of shouldComponentUpdate that is especially useful when a single instance of a component out of thousands should update and the others should stay the same; it's a technique I use in this demo (try it out in an incognito window; I've found some Chrome extensions make layout/repaint times much higher—for me, adding/removing single elements once the list is 1000 long takes ~13ms, changing the size/color of an element takes ~1ms). However, it does no good when every element needs to update.

My guess is that Angular will be faster at changing most or all of the elements in your table, and React will be quite proficient at updating select entries when using shouldComponentUpdate.

Laurel
  • 5,965
  • 14
  • 31
  • 57
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 1
    I am looking at your demo and trying to figure out react's Virtual DOM / rendering benefits. What I see is that for each list item I am adding, page's layout is painted again (please take a look at this http://prntscr.com/6qfgqv ). I am confused - shouldn't react render only what changed in the actual DOM? Can you please help me understand this? – Yaniv Efraim Apr 06 '15 at 20:01
  • Regarding my last comment. After further investigation of your (Awesome!!!) demo (No 6), I understand the benefit of react rendering only new elements and not the entire component, without you having to take care of this. But, still, the document will have a full layout/paint. Isn't this missing the whole point of React (again, I'm confused about that..) – Yaniv Efraim Apr 06 '15 at 20:33
  • @Yaniv I think your assertion that the document will have a full layout/paint is not necessarily correct (or at least not always correct). I'd have to look into React's DOM reconciliation code, but I think that if a sub-component changes, only that HTML is changed. The repaint can be due to styles, box model, etc. For example, my demo6 used to be much slower on repaint until I moved some inline styles to a stylesheet. – Michelle Tilley Apr 07 '15 at 15:45
  • @BinaryMuse which tool you are using to check performance? I am curious to know? – Jaydev Nov 18 '15 at 14:24
  • 3
    @Jaydev The Chrome developer tools; check the "Timeline" tab. – Michelle Tilley Nov 18 '15 at 15:45
  • @MichelleTilley my timeline tab does not contain a detailed description of execution and rendering. if it's not to much trouble, i and many others would appriacte if you can tell us how to use it so it does show all the info including the actual javascript called. just like in your great answer. – eran otzap Feb 18 '19 at 18:09
3

I'm surprised nobody mentioned PureRenderMixin. It implements shouldComponentUpdate so you don't have to worry about it.

Also, I wonder if React Performance Tools would turn up something useful?

And I'm surprised to hear Angular is faster than React after watching this talk from Ryan Florence.

Stoutie
  • 1,944
  • 1
  • 21
  • 17
3

We have tried to analyze some of the attributes of our frameworks, of course, this is not the whole list. Below there is a table of consolidated and important, in our opinion, of comparing attributes.

enter image description here

Let’s get some more details:

enter image description here

enter image description here

Although Angular vs React differences are many, they can do the same thing, namely to build client interface. Both have their place. For those peoples who like web development above all interesting is innovative AngularJS approach to HTML.

AngularJS really is a full framework and not just a library, as the ReactJS, but ReactJS has better performance than the AngularJS by implementing virtual DOM. In our opinion, you should use AngularJS if:

  • you plan to carry a lot of unit tests during development,
  • you want a comprehensive solution for your application.

However, two-way data binding is often touted advantage of using AngularJS, but because it is implemented through a series digest, adding too much complexity for certain functions and expressions can lead to deterioration in performance of your applications.

John Skiter
  • 196
  • 2
  • 3
1

In this particular case you need to be aware that the state trickles down and so do the DOM updates. What you want to do is create a Price component that stores the locale in its own state and receives a signal (ie channel or flux) to change the locale as opposed to sending the locale prop all the way down. The idea is that you don't need to update the entire Numbers component, just the prices inside. The component might look like:

var Price = React.createClass({
    mixins: [ReactIntlMixin],
    componentDidMount: function() {
        subscribeToLocal(this.onLocaleChange);
    },
    onLocaleChange: function(newLocales) {
        this.setState({locales: newLocales});
    },
    render: function() {
        return <span>this.formatNumber(this.props.number, this.state.locales, {style: 'currency', currency: 'USD'})</span>
    }
});
zbyte
  • 3,705
  • 1
  • 17
  • 13
  • 1
    This will not be much faster, and a quick and dirty test with an EventEmitter shows that's the case—with 2000 `Price` components, the channel/flux store/etc. will still need to iterate over 2000 listeners and `setState` will be called for each. – Michelle Tilley Oct 31 '14 at 06:46
1

In React component, once you call setState, it will trigger the render function immediately. React will mark this component as dirty, and will re-render all the children element inside this component.

It will not render the whole Native DOM elements because of the Virtual DOM, thus it will still create new instances of its children ReactElements, which can lead to extra Javascript memory cost.

To avoid this issue, you need shouldComponentUpdate function which implemented in Component Class. it will executed before Render method. If you find the there is nothing changed right now, for instance in your example, you change the state.locale. You can definitely consider this component need no update. so just return false to prevent the render call.

This is a base solution to solve React performance issues. Try to add "shoudlComponentUpdate" in your Numbers Component to avoid tons of

  • element re-render
  • hlissnake
    • 229
    • 2
    • 3
    1

    This is an example where all that is changing is one data output. It's not impossible that Angular's two way data-binding simply offers a faster re-render when all that is changing is the display of the bound data.

    React does not promise that its renders are faster than any other framework under all circumstances. What it does offer is the ability to handle ~arbitrarily complex DOM updates in very efficient manner, and offer a variety of lifecycle methods (e.g. componentWillReceiveProps, componentDidUpdate, in addition to the afore-mentioned shouldComponentUpdate) to let you fire callbacks on those events and control how and if they should happen. Here, there's very little to optimize, because all you are doing is changing 2,000 text displays.

    edit: To clarify, React is useful in doing more complex DOM manipulations because it's virtual DOM algorithm allows it to choose the minimal set of DOM operations necessary to update your DOM. That's still a lot of work to do when all that needs to be happening is 2000 instances of some text changing.

    Joel Tadmor
    • 121
    • 5