At Synergy Codes, we have been dealing with data visualization for (almost) a decade. GoJS is our primary weapon, and we’ve linked it with React most of the time, but over the past year, the number of Angular project inquiries has grown significantly. This made us adapted to the market and mastered the GoJS + Angular connection. Until now, we are selecting a partner for a diagram library depended mainly on the customer’s existing infrastructure or his requirements.
However, we’ve recently had inquiries about “bare” Angular or React projects made from scratch without implementing the GoJS. It led us to consider the superiority of one over the other. One of the essential criteria is performance, and we would like to focus on this topic today.
Assumptions of the test
We decided to explore this aspect somehow and draw our conclusions. To make a meaningful test, we needed to make some assumptions. Testing on production builds was paramount – we don’t want the developer mode facilities to affect build times, pack size, and overall app performance. Both applications should also have analogous component trees, the same HTML structure inside, and identical CSSs.
The applications must also contain a list with many elements; we will test the results for several different orders of magnitude. For each of these orders of magnitude, we will repeat the test ten times and take the average results. We will only test the latest version of Google Chrome, each on their computer, but we will have the identical Node versions.
Selecting the measurement method
The topic is not straightforward because of the comparison of two different worlds – React and Angular reliably. These worlds have some built-in methods for measuring performance, but they will likely measure them differently as they are their implementations. It leads to the conclusion that the obtained results prove to be unreliable. Another way would be a simple console.log() placed in the correct place in the code. However, identifying this “right place” can be pretty challenging as we will be dealing with two different technologies.
This tool also measures the current memory consumption, which is a noteworthy addition to see in practice the differences in resource management between the Virtual DOM used in React and the Incremental DOM used in Angular.
Overall, the choice fell on Google Chrome and its built-in performance measuring tool. We assumed rendering duration and RAM consumption as the comparison criteria.
Let’s move on to presenting the structure of our test application.
Description of the test application
The application on which we will test Angular/React performance is relatively simple. We are dealing here with the basic structure of the application (header, content, and footer). This application generates a list of the company’s employees with their name, surname, position, and age. We can easily manipulate data to force re-rendering in the footer, i.e., we change all employees to the “backend developer” position. We will also find the possibility of changing the number of employees, which will be critical to check how the selected technologies can handle a bigger data sets.
In addition to the re-rendering, we have options to add and remove an item from the list.
We have prepared the applications in such a way that they have similar DOM tree structure. We used the basic methods available without any external Redux state management mechanisms. So in the case of React, there’s a usual “props-drilling” to pass the updated state. However, it is connected with the necessity to refresh practically the entire structure of the application. In Angular, we used the OnPush change detection strategy, and in both cases, we gave unique keys to the list items (key in React and trackBy in Angular). We expect React to handle the full-view rendering task faster but expect faster but with a higher memory footprint. Used in React Virtual DOM allows for high-speed handling of changes but requires many complete copies of the DOM tree kept in memory. Also, mechanism to compare differences between these virtual trees has to be loaded in the memory. With Incremental DOM, Angular doesn’t require that much memory but loses speed instead. We also assume that the created application will be much smaller in React, as it is “only” a library for building user interfaces – Angular as a full-fledged framework contains a lot of functionalities that React does not have by default.
As we mentioned before, the time/memory measurements were made using the built-in development tool in Google Chrome (Performance tab). We measured the overall execution time for a given task based on visible function calls in the tool. In the attached picture, the area with functions causing the rendering of elements is marked. They were made from the “mouse up” event, which in our case meant clicking on the option from the list that indicated the number of items. The following steps are page layout conversion and internal (React in this case) calls.
The measurement itself was as follows:
- We refresh the page.
- We start recording the profile in the tool.
- We perform the following tasks in turn:
- we choose the number of elements,
- we add a feature,
- we remove the element,
- we change all the elements.
- We are finishing the profile recording.
- We analyze the results by selecting appropriate ranges.
It is also worth adding that the final measurements are the average of 10 results. In addition, they were made on two different machines. For the maintenance of the reliability of the results, each measurement was performed in an “incognito” mode.
So let’s move on to the tests.
First rendering of elements
It is an excellent time to mention the production sizes of application packages – for Angular, it is 166.98 kB, and for React, 48.44 kB.
The above chart shows the dependence of time on the number of rendered elements. With a small number (10 and 100), the total render time, although it differed, did not affect the user experience in any way. However, it can be seen that for 100 items, the difference in time measured was two-fold. Problems start when trying to view 1000 items at once. Here React comes to the fore, as the average time is more than three times smaller. The difference was visible to the naked eye during the tests themselves. As the number of elements increased, the gap between React and Angular grew deeper. It is also worth noting that the difference between 10,000 and 20,000 was roughly two-fold in both cases. So we can assume that the relationship between the number of elements and time is linear.
The graph above shows the dependence of time on the number of elements when they are re-rendered. Here, as with the first render, React is ahead. There is a significant difference with the number of 1000 items. In the case of 20,000 elements, the difference is fivefold. Most likely, this is because React is very good at changing components through the use of Virtual DOM. As you can see, in practice, this approach is more efficient than the Angular solution, at least in terms of the time aspect.
Adding a new item
The following chart shows the dependence of time on the number of items for adding a new item to the list. Here it is a bit different. Angular fared much better in almost all cases (except ten elements). Interestingly, the most significant difference is 1000 elements, where Angular was, on average, over four times faster. You can also observe some flattening of the graph between 10,000 and 20,000 elements. The absolute time difference between Angular and React is then quite similar. What could be the reason for Angular’s advantage in this case? The most likely cause is the structure of the application. In the test, we assumed that we use the “props-drilling” method to manage the condition in React. As the component for displaying the list was in a different place than the button for refreshing it, practically the entire application structure had to be re-rendered. This overhead may be due to just re-rendering of things that didn’t necessarily have to render.
Deleting an item
There is also a graph of the time dependence of the number of elements in removing one of them. Here the differences are not that big, but I must admit that Angular is in the lead again. The reasons for this can be similar to adding items, i.e., “props-drilling” can cause HTML nodes that were not necessarily involved in the delete operation to re-render. Nevertheless, the removal time for many items can be considered acceptable in both cases.
In the end, we are left with the analysis of memory consumption in all of the scenarios mentioned above. We used a candlestick chart to present the data, where each candle provides information about the average memory consumption and the extremes. The candle body represents the range between the average minimum and average maximum memory usage. Candle wicks are responsible for the extreme values - a one-time minimum and maximum derived from the set of all measurements. The candles in the chart are grouped: each “list size + action” pair has two candles, with blue (left) representing Angular and white (right) representing React. Appropriate captions are located on the X-axis, more expansive spaces separate sections related to the given list size. With 10 and 100 elements, memory consumption is generally deficient. React is slightly better at 10, and Angular is just as somewhat better at 100. With 1000 elements at peak moments, the consumption reaches 20 MB, and, surprisingly, Angular is responsible for this result. With this size of the list, React only minimally lost when the entire list was re-rendered. For larger list sizes, the results for React start to grow dynamically, including an increase with the application runtime. Angular doesn’t have this problem; memory gain is more stepped. Each subsequent action is within the memory range needed for the first render. React continues to grow while the application is running. It is a signal that you need to take care of optimization if you have a sizeable interactive list in the application.
We have dealt with the performance comparison of applications written with Angular and React. However, this is only one of the factors that can be used when choosing technologies for your project. What’s more, it should rarely be the dominant one.
We’ll cover the remaining factors in the webinar on September 15th, where we’ll try to answer the question, “When is React a manual, and when is an electric screwdriver” We invite you to it now!
If you’re looking forward to the webinar, below is the first episode of our new Synergy Caffe series, which also covers the Angular vs. React comparison. We encourage you to follow the entire series; another episode is coming soon!