Is AngularJS Fast Enough?

“Angular is slow. And with dirty checking and HTML parsing always will be. You can’t fix broken design. Do I have to tell something about consequences for mobile web apps? I guess not.” — from What’s wrong with Angular.js

For Daniel and many React devs, there is no debate. If you care about performance, you use React instead of Angular. Period.

I don’t think it is quite that simple. Performance is a means to an end. The real goal is providing a great user experience. No doubt speed matters, but not all changes in speed are perceived by humans the same way. This chart from O’Reilly shows how there are buckets of human perception:


So, when you think about whether Angular is “fast enough” for your needs, forget about the benchmarks comparing different frameworks. Here are four much more important questions you should be asking yourself:

  1. Is it possible to get near instantaneous initial page load?
  2. Do simple pages operate within the near instantaneous bucket without much effort?
  3. When performance issues do come up, is it possible to optimize any issues down to at most a small perceptible delay?
  4. Does your app perform on mobile devices?

Initial Page Load

A common problem for most client side JavaScript frameworks is that the initial page load experience can be quite awful (1,000+ ms). There are essentially two strategies for optimizing initial page load: ultra-fast bootstrapping or server pre-rendering.

Optimizing the bootstrap process involves breaking up the client app into pieces so that only resources needed for the initial page load are downloaded at first. Other resources are then lazily downloaded in the background. Angular doesn’t enable lazy loading, but Ben Nadel shows that it is possible. Lazy loading will also be a key feature of the Angular 2.0 Dependency Injector. Even with this, however, it is likely going to be hard to get under 100ms.

The only proven way to do that is through server pre-rendering. There is no easy way to do this with Angular, but there are two viable options. You can always duplicate your rendering logic on the server in another framework or even another technology. This isn’t ideal, though, because it takes a lot of work to keep the duplicated logic in sync. The more ideal solution is to leverage Isomorphic JavaScript where the same code is used on the client and server. The Angular team gave up on the idea of building server rendering into the framework, but it is possible. We are working on a library at GetHuman called Jangular that renders Angular on the server. Our tests so far confirm that we can get Angular initial page load times under 100ms.

Simple Apps

Let’s be honest. When you compare simple apps, the performance difference between client side frameworks is negligible. Don’t believe me? Take a blind tour through the TodoMVC apps and try to guess the framework.

Angular operations with few bindings on a given page are almost always under the 100ms mark. Whenever I have noticed performance issues with simple pages, it is inevitably caused by something outside Angular (usually due to a poorly performing API call).

Complex Apps

Todd Motto does an excellent job of explaining why large Angular apps can suffer performance issues. The gist is that Angular adds watchers for every binding and many directives. Larger apps can start to approach the infamous Angular 2000 binding threshold when performance degradation is noticeable.

(edit) As Igor points out in the comments, 2000 bindings is not the actual issue. The issue is slow expressions (ex. ng-if=”doesExist()” where your custom doesExist() function takes 2s to return).

There are four primary strategies that should be used when dealing with complex Angular apps.

  1. Don’t create complex Angular apps. Just because an Angular code base is large doesn’t mean it has to be complex. (edit) I have received a lot of feedback on this point because of the confusion of what it really means to be “complex” and how exactly you can create a large, simple Angular app. I am going to dedicate my next post to this subject and add the link here when it is done.
  2. Limit watchers. Read the Todd Motto article in depth for tips on how to limit how many watchers are created by Angular in your app. (edit) With Angular 1.3 this advice seems to be out of date. Igor says that if you still experience this issue with 1.3, you should submit a bug. Also, two great tools that can help find performance issues with watchers and/or watch expressions are ng-stats from Kent C. Dodds and Batarang from Brian Ford.
  3. (added based on Igor’s comments) Simplify the expressions used for bindings and evaluated by directives. If most of your expressions are single scope variables or very fast functions then Angular can handle many more bindings without breaking a sweat.
  4. Go outside Angular. Simply wrap the external library with an Angular service or directive. (edit) Note that are a number of DOM manipulation optimizations with Angular 1.3 which should make this less necessary.

Some examples of optimizations made by going outside Angular include:

Also, keep in mind that there are a number of optimizations on the way that will make this even less of a problem. Angular 1.3 introduces many optimizations under the hood and some new features like one time binding. Angular 2.0 will include Zones.js which will cut down on the number of digest cycles and many more optimizations. Perhaps the biggest impact, however, will come when browsers support Object.observe(). As Brad Green explains,

The end result of [Object.observe()] will mean that Angular’s (already blindingly fast) data-binding performance goes from O(n) to O(1) and will scream no matter how many elements you have on the page.

(edit) As Igor mentions in the comments, Brad may have overstated the effect of O.o() (the abbreviation for Object.observe()) just a little bit. Regardless, O.o() will have a positive impact on Angular performance.

Mobile Apps

If you are building an Angular native or web app for mobile, you will almost certainly want to utilize the Ionic Framework. Ionic was built on top of Angular and is able deliver performance that you cannot achieve with Angular by itself.

Also keep in mind that Angular 2.0 is being designed specifically to target mobile apps. It is unclear exactly what that means now, but it is good news.

Conclusion

Going back to the important questions I posed:

  1. Is it possible to get a near instantaneous initial page load? Yes, use server pre-rendering.
  2. Do simple pages operate within the near instantaneous bucket without much effort? Yes.
  3. When performance issues do come up, is it possible to optimize any issues down to at most a small perceptible delay? Yes. These issues do not come up often, they are coming up even less frequently as more optimizations are added to Angular and there are a number of ways to resolve any issue that does come up.
  4. Does your app perform on mobile devices? Yes, use Ionic.

React or another client side JavaScript framework may beat Angular in certain performance benchmarks, but that in no way prevents applications built with Angular from providing just as good of a user experience.

So, is AngularJS fast enough? Hell, yes.


(edit) A lot has happened since I wrote this article. Angular2 is in alpha and appears to have completely eliminated any performance concerns that exist in 1.x. I strongly recommend watching Dave Smith’s ng-conf presentation to get a sense how drastic the change is from 1.x to 2.0 performance.

Like what you read? Give Jeff Whelpley a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.