When Angular first started it was a significant improvement over existing frameworks. We no longer had to set every single attribute or trigger an event for any change in the UI. It was pure magic, just add your binding to the view and that was it. I, as so many others, was really excited about it. It was a lot better than some other frameworks at the time. Now, after a year of working with an enterprise level Angular app, I feel not everything in Angular is magic. That being said, great apps can be built with Angular.
These are some of the lessons that were incorporated as our application grew larger:
Do not overuse Resolves
We have to be mindful with added latency for each of the resolves used. If we pile multiple resolves for a single route, we create a synchronous operation that will block the application. Meaning that nothing else in the Angular app will execute while the resolves are getting data. We also noticed that while the resolves were getting fetch, the router would not even register correctly the events for browser back and forth.
A better approach is to load resources on the screen asynchronously as soon as they are ready. This will give the user the impression that the app is loading faster.
Trim the fat
As our application grew, we noticed some decline in performance, specially on Windows machines. On our Mac machines, we never noticed any issues on the browsers, but as more users started playing around with the application, the issues became evident. It got so bad that on some machines, after 30 minutes of continuous use, the application was crashing.
- Profile the application. Chrome inspector provides some great tools to accomplish this. You can profile memory heap, and javascript execution. While profiling the application, we found that the $digest function was being called multiple times. This led us to identify one of the areas we needed to improve.
- Reduce the amount of $$watchers used in the application. Basically, any binding not required to change at runtime was changed to single binding. For Angular magic to happen, it needs to include a loop that checks for any possible mutation in the scope. For small applications this is not an issue at all, but as the application grows (like we soon noticed), it is an issue. Adding the single binding is really easy, just add :: to the binding and that’s it.
- Optimize the ng-repeats: there are several improvements that can be done around the ng-repeat:
Always use track by:
<div ng-repeat="a in arr track by a.trackingKey">
Instead of:
<div ng-repeat="a in arr">
By adding track by, the rendering of the repeated elements is more efficient. This will tell Angular to only render elements needed rather than to have to recalculate and re-render all the elements in the list.
We also remove any function call to parse or process data inside the ng-repeat. Rather than parsing data in the template we always parse data prior to binding it.
- Ng-if vs Ng-show/ng-hide: while visually two directives look similar, their effect is very different. ng-hide/show only toggles the display CSS property. So any binding that you have in that part of the template is still being applied and processed. Ng-if adds or removes the node from html altogether. In this case, it will also remove their corresponding bindings. While using ng-if seems like the best approach, that may not always be the case.If there are nodes that are being toggled constantly, it is better just to hide them (ng-show/ng-hide). If you have big nodes with multiple bindings that are not being toggled all the time then ng-if is the man for the job.
Learn from the community
As any developing process, we are constantly learning new techniques, new practices. Always look for the experience provided by the great Angular community. Angular is a mature framework with a great online community. And while there are great options like React.js and others, Angular is not going away anytime soon.