Is React Fast Enough?

by Daniel Eloff — Full-Stack Developer

Lovable Technology
12 min readAug 1, 2018

Motivation

Single-page thick-client applications have become all the rage now, popularized by Angular, React, Vue.js, Ember and other JavaScript frameworks. They offer the ability to construct a rich, interactive user experience using client side JavaScript and better performance through use of a virtual DOM (except for Angular, which uses a different technique.) They feature component-oriented development which promises cleanly encapsulating UI elements and functionality in reusable components. Both big companies and startups are jumping on the bandwagon, but I personally recommend a more measured approach. As with all technology trends, there are a variety of advantages and disadvantages to every technology, and achieving the best result means playing to the strengths of the framework while minimizing the drawbacks. How well you can play that game depends very much on what kind of company you’re in, and what kind of application you’re building. Switching between frameworks or client-side and server-side rendering carries a heavy switching cost and comes with substantial lock-in. It should not be a decision made lightly, and should involve careful consideration of the pros and cons. I’ll spend a little time highlighting some of the pros and cons here as I see them, but I will also be taking a more empirical approach by creating a simple web application as an SPA using React and as old-style server generated HTML using Go’s standard library templates, pitting them head to head in implementation effort and performance.

The Experiment

I’m going to implement a small but complete sample web application using a shared Go backend and both React hotness and “boring” old Go templates for the frontend. I will compare these implementations on the amount of effort spent coding them, code maintainability and complexity, and the time from request until rendered in the browser. For both first load and subsequent requests. Then we’ll look at the results and some common pro and con arguments and draw some conclusions about when to best use one or the other.

The application will be a simple appointment scheduler. A business will set some initial blocks time that they are available during the week (e.g. normal operating hours). The application simply shows a pageable series of weeks showing all of the appointment blocks and allowing booking of available blocks.

It won’t win any design awards, but it’s just complex enough to make for a good comparison.

The Hypothesis

My theory is that React really starts to become more important on very large projects. My gut feeling is that the speed and simplicity of server-side rendering is underestimated. I think it’s likely that a server-side only solution will yield better page load times, with less code and time spent in development. I think round-trip latency will probably dominate the time between request and page render for both solutions. But the programmer’s rule of thumb is always to measure, not to trust our gut feelings with complex systems, because there’s a lot of room for surprises.

The Argument for React

I’m talking specifically about React here, but many of the arguments are equally valid for other SPA or thick-client frameworks. One thing React really has going for it over other similar frameworks is the size of the ecosystem. There is a lot of information available on just about any topic in React, which definitely helps whenever you run into trouble. It makes it easier to find developers with React experience, so they won’t need as much time to become a productive part of the team. But something else that I rarely see mentioned is React is a platform. It provides a common way to define self-contained components that can be shared and imported into your project. Many components that you might think of building are just an npm/yarn install away. It also makes it easier to share components between multiple projects in the same company. That’s an underestimated advantage in favor of React that will strengthen over time. Component oriented design is hardly new, but having a common framework that allows for combining components from different sources in a predictable way is a big improvement over the prior state of web development. This is an advantage inside large organizations because components developed by different teams may be shared, even across divisions and projects.

The other central advantage of React and frameworks like it, is it makes it easy to create rich, interactive user experiences. One can do that by adding client side JavaScript to enhance your server generated content, but it’s not nearly as clean or as simple as with React. React is a clear win over the previous approaches of modifying the DOM with the help of tools like jQuery. However, it’s worth noting that having a rich, interactive user experience is not necessarily a business necessity. It very much depends on what you’re trying to do and who the target audience is. Having a very heavy client environment with megabytes of scripts and images could work against you, especially on mobile devices, and especially outside the developed world. Google is a great example of how a company can be successful with a minimalist UI. However, if you want to develop a richer client experience, there’s no doubt that frameworks like React can help you organize your logic and styles in a more composable, maintainable way.

Using popular new technology like React will likely have the benefit that your team is happy that they’re getting experience in marketable skills — it advances their career. It may also make hiring more difficult if you need to hire for those skills in addition to what you usually hire for.

The Argument Against React

Search engines are getting better in that they have some capability to execute and index JavaScript generated content. However, this is still somewhat limited, undocumented, and varies between search engines. It seems that doing certain things like loading data asynchronously or linking between pages in an SPA can cause problems for search engines. I was unable to definitively answer the question one way or another if this is still true in 2018, it seems as if it’s at least partially true. The very fact that it can’t easily be answered should give you pause. If your content is not gated behind a login, and SEO matters to you, then you may still need to be able to render it server side to achieve equal results in the main search engines. This can be achieved with React using headless browsers or frameworks like Next.JS but that’s going to add quite a bit of work and complexity. On a big project it might not matter too much, but for a startup complexity is death.

Modern software development feels like building up an ever deeper cascading layer of Russian nesting dolls. Abstractions layered over abstractions with frameworks, libraries, and APIs all the way down. This is good, because ever more powerful abstractions allow software developers to accomplish more with less time. However, every abstraction leaks and the developer still greatly benefits from understanding the details of how each layer is constructed and operates — to a lesser extent the further down in the stack you go. React offers powerful abstractions, but it also brings a large number of concepts and implementation details that must be understood in order to use it effectively. There’s no doubt it will take some time for a developer who has never used React to become a fully productive member of the team. Then there’s the source code translation and webpack magic that can be quite frustrating, and in my case anyway, also a time sink. I find the source translation to bring many of the disadvantages of a compiler, slower edit-run-debug cycles, the need for source maps to map back to the original code, but without the advantages of static typing (unless you use TypeScript.) So certainly one advantage of using old-school server generated HTML is that you don’t need to learn React and its quirks, or deal with webpack. Keeping things simple is underrated, especially in a startup where time is limited and all energy would be best focused toward finding that pot of product-market fit at the end of the rainbow.

The Results

1. The RTT from the server is measured at 44.4ms using ping. Server response time is Initial load is measured as first paint time in Chrome, this comes shortly after DOMContentLoaded and Window.onLoad.

2. The first paint time for React is the wrong thing to measure, because the data is still loading into Redux via an AJAX call. Instead I measured the time that the AJAX call completes, but this is overly generous to React because the response still needs to be parsed and React needs to render. The initial load time is already so heavily in favor of Go templates that it hardly matters. There are some tricks that can be played to embed the initial data with the index.html, thus eliminating this AJAX call all together.

3. If the browser has a connection open to the server that can be re-used, this time decreases by 46ms. This is true for example if the page loaded, or another AJAX call was made within the keep-alive window. This demonstrates the importance of configuring longer keep-alive times on the server. For whatever reason, there is no equivalent effect for following the server-side reserve link. I can’t think what could technically prevent the browser from making the same optimization in this case, but at least the latest Chrome does not.

Interpretation

If you remember from my hypothesis, I predicted that the Go templates would win over React in lines of code, development effort, and performance. This was indeed the case, to an even greater extent than I expected. React turned out to be 2.5 times more lines of code, and 2.1 times more effort. Very little of that was in one-time costs, like setting up the initial boilerplate. Generated or copy-paste boilerplate code was not counted. Code shared between both implementations was not counted, which was the majority of the work. The React app is lacking critical things like being indexable by search engines, a busy indicator during requests, and handling of scheduling conflicts (if two users try to book the same appointment slot.) By virtue of each action refreshing the entire page, we get that for free in the server-side solution. To be fairly considered functionally equivalent, those features would need to be added. But there was just so much time I was willing to devote to a toy example. React is more time consuming and verbose by a solid margin, but the precise amount will vary from project to project.

JSX is actually very nice as a “template” language since it gives you the full power of a programming language. Go templates are intentionally limited, and that meant changing and adapting the backend code in unnatural ways to suit the limitations of the view layer. I strongly disagree with the school of thought that thinks the view layer should be limited. There’s nothing wrong with having complex view logic in the view layer. If you can’t be trusted to keep backend logic out of the view layer, that’s another issue entirely — but shouldn’t outlaw tools just because some people can’t handle them responsibly. The React code was far more verbose, and took more time to write, but it felt like I was fighting less with my tools to write it.

Where I turned out to be wrong was that once the React SPA had loaded, subsequent actions were 29% faster than the server template solution. This became even more marked, 2.5 times faster, if requests are made close enough together in time to re-use the same keep-alive connection. This is worth calling attention to, as it was a wholly unexpected effect. There doesn’t seem to me to be a technical reason an AJAX GET can re-use a connection, but a regular GET cannot. The tests were done with Chrome, and I did not investigate if the effect holds up in other browsers, or if there are other ways of mitigating it, like through server configuration. So React has a clear win on performance and “reactivity” once the SPA has loaded, but a clear loss in the initial load time. However, one must be careful drawing too many conclusions from the initial load time, because this is a toy app and neither version of it is even slightly realistic. There are too few scripts, styles, and image assets to make a realistic test. I would expect that the differences begin to converge as you add more content. React with webpack makes it easy to minimize and bundle your JavaScript and CSS into fewer files, which you should always be doing.

I expect one could also get convergence between the solutions by adding a little bit of JavaScript and executing the server-side actions as an AJAX call and then doing a partial DOM update with the response HTML. I didn’t test this, but I don’t think it’s controversial either. So while the server-side application wins on the initial load, and React wins on subsequent actions, one could very likely mitigate these differences in a real application. I would therefore place more weight on the differences in implementation complexity and time than on the performance when evaluating this experiment.

I expected round trip latency to dominate, which was true. A request, be it an AJAX request or a regular GET involved one RTT to open the TCP connection, and another to do the actual request. If SSL were being used this should add an additional round trip. The actual time for the server to render or return the data was just one or two milliseconds, and React took a little less than ten milliseconds to render. Everything else of note, which was always the vast majority of the time, was caused by the round trip latency.

All of the code is available on github: https://github.com/eloff/react-vs-go.

Functional React — Reducing Verbosity

Dosty Everts, a coworker of mine, proofread this article and decided my React code was overly verbose. He whipped up a version in functional React style that’s a lot lighter-weight. It should be somewhat quicker to code as a result, but it’s difficult to say how much faster since it’s easier to rewrite an existing system than to write one from scratch. Dosty has the following to add to the conversation:

One big criticism of React in this blog post, is that it’s more verbose. After seeing the Go template, I certainly agree that Go templates are less verbose. At the same time, I wanted to ensure that we’re presenting an iron man for React, rather than a straw man.

Here began my attempts at making our React example less verbose. To start, I took our React components and converted them to functional stateless components. React lets you define a component as a function that takes one props argument and returns the markup you want to render.

Then, I used Array prototype methods to map array props to the components we wanted to render, instead of using for loops.

Lastly, ES6 arrow functions were used for simple inline functions and implicit returns. These changes can be seen in the functional branch of the github repository.

I was able to reduce the LOC in the Day and Schedule components by 41 LOC. At the same time 25 LOC was moved to a new component to determine the time to make a reservation and redraw, so take from that what you will. Nevertheless, we’re still at twice as many LOC as the Go template implementation.

Conclusion

Hopefully if you’ve made it this far, you’re reading with the open-minded show-me-the-data mindset of a scientist, rather than with a goal of confirming whatever biases you may have held before reading it. I think the data and the arguments I made demonstrate that both React and server-side HTML templates have their use. Server side templates were a clear win in terms of development costs and complexity. A single-page React application can have better performance, but it is likely possible to close this gap with judicious use of AJAX. React is the clear winner if you need to develop a rich client experience. Due to the switching costs involved, if you think this is a requirement or will become a requirement, you’d likely be better off starting with React. The React ecosystem is growing rapidly, and the amount of ready made open-source and third-party components that can be integrated into your application are another important consideration. React is also more structured, and one will likely benefit from this when working in a larger team. Because code is read more often than written, this added structure may actually let React pull ahead in velocity in a large enough team, even if it’s more verbose.

Given all these strengths, React (or perhaps something like it) should probably be the default choice for a new project. However, there is one scenario where I would disagree. If you’re working on a scrappy project with very limited time and or funding, like in a startup, I would strongly recommend to stick with the more traditional server-side template solution. You’ll save a lot of development time, you won’t get distracted by implementing “shiny things” and those advantages may very well make the difference between a successful venture and a failed venture. It’s boring, and the result won’t win any awards, but it will be quick, predictable, and functional. Startups are all about iterating as fast as possible, and delivering bare-bones, even embarrassingly rough features. I think the old software adage of building one to throw away makes perfect sense for a startup. Do it quickly with a minimal UI first. Then do it right when you’ve got the breathing room afforded by success, funding, or a strong head start on the competition.

--

--

Lovable Technology

World Class Engineers and Designers Helping You Ship Lovable Web and Mobile Technology.