Angular JS Scaling & Performance
Solution 1
You need to create custom directives in order to curb the performance issues with angular. Unlike ember angular comes with all the bells and whistles turned on and it's up to you to tone it down. Here are a few directives I've created to help you out. Not all data in your app needs to be two way data bound and as a result you can save valuable cpu power by forgoing watch expressions in the page where needed. All of these directives bind data one time and leave it alone.
https://gist.github.com/btm1/6802599
https://gist.github.com/btm1/6802312
https://gist.github.com/btm1/6746150
One of the answers above talks about ng-repeat having huge performance hits so I give you "set-repeat" a one time data binding repeat directive :)
Solution 2
It is hard to provide a solution without more information about your problem, but I recently experienced (and solved) a performance issue that may be similar to what you saw, and was unrelated to the $digest cycle.
Most discussion of angularjs performance you will find (including the excellent post from Misko) is about the performance of dirty checking and the $digest cycle. But that is not the only performance issue you can experience with angularjs. The first step should be to determine if the digest cycle is your problem or not. For this, you can use batarang, or just look at your app and at when precisely it is sluggish. When the digest cycle is slow, essentially any interaction with the UI will be slow.
OTOH, you can have an app with a fast digest cycle, that is slow only when loading, switching views, or otherwise changing the sets of components to display, and this can manifest in profiling as a lot of time spent in parsing HTML and garbage collecting. In my case this was solved by doing some pre-computation of the html template to display, instead of relying on ng-repeat, ng-switch, ng-if everywhere.
I was using an ng-repeat="widget in widgets" containing an ng-switch on the type of widget, to display an arbitrary set of widgets (custom self-contained directives). Replacing this with code to generate the angular template for the specific set of widgets sped up route switching from ~10s to practically instant.
You can see the google groups thread above for a little more info on how I solved my particular problem, or provide more information about your application if you want some specific suggestions.
Solution 3
To improve performance in production read very nice one-liner below:
Quoting AngularJS Documentation:
By default AngularJS attaches information about binding and scopes to DOM nodes, and adds CSS classes to data-bound elements:
As a result of ngBind, ngBindHtml or {{...}} interpolations, binding data and CSS class ng-binding are attached to the corresponding element.
Where the compiler has created a new scope, the scope and either ng-scope or ng-isolated-scope CSS class are attached to the corresponding element. These scope references can then be accessed via element.scope() and element.isolateScope().
Tools like Protractor and Batarang need this information to run, but you can disable this in production for a significant performance boost with:
myApp.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}]);
You can read more details here
Solution 4
Generally, AngularJS will perform poorly if there are more than 2000 data-bindings active, i.e. 2000 items in the scope that are being dirty-checked each $digest-cycle. Ng-repeat has a big performance impact because of this; each repeated items sets up at least two bindings, not counting any additional data or directives that are used inside the item.
One of the developers behind AngularJS gives an excellent description of the details of dirty-checking, and its performance in this SO answer:
https://stackoverflow.com/a/9693933/179024
The comment thread below that answer is worth a read, and I also share some thoughts about it in an answer further down on the same page:
https://stackoverflow.com/a/18381836/179024
Solution 5
try avoiding the following
- please avoid using ng-repeat if you have more than 50 elements in the list at a time and avoid manual watches
do not use ng-click, ng-mouseenter,ng-mouseleave etc mouse events blindly till it is a dire need , try to reduce their numbers by using $event object along with event propagation concepts of js
-
where ever possible use scope.$digest instead of scope.$watch, this ensures that digest cycle is executed only on the child scopes
- try having nested scopes i.e. one or two controllers inside one parent controller and keep the reusable logic in parent , i used this in nested states while using Ui-router (to fulfill a req where change of URL was required without page refresh ).
most important! REMOVE ALL FILTERS FROM HTML!
all the above trigger a digest cycle on all the scopes of your application so there is a high probability that even when the view has been rendered angular is again executing relentless digest loops
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on July 28, 2022Comments
-
Admin almost 2 years
We are pounding our heads against performance issues with an Angular app we are building for a bank.
Unfortunately, it is a breach of contract to show snippets of the code. Regardless, I can describe some of the main issues going on, and I am hoping that best practice can be recommended.
Applications Structure:
- Essentially, a giant multi-form page.
- Each form is its own partial, with nested controllers and partials about 3 levels deep.
- The same forms are ng-repeated over a collection of json objects.
- Each form is bound to the object / model that it is repeated over.
- We are supposed to support anywhere from 1-200 forms on the page.
If you take a look at the timeline. We are spending a great deal of time in the jQuery parse html method, jQuery recalculate stye method, the GC Event (Garbage Collection). I imagine minimizing these should speed things up a bit. They are all a part of the Angular lifecycle, but there may be better ways to avoid them. Here are some screenshots of the profiler:
Ultimately, the app is sluggish as the number of repeated forms goes above 5. Each form is relatively unrelated to the others. We have tried not to watch any shared properties between the forms.
-
DNS almost 11 yearsI think Misko's answer, while great info, only partially addresses this question. A big part of the issue here appears to be that Angular is creating each element individually, rather than batching them into the same fragment.
-
MW. almost 11 yearsThe issue could simply be that with a number of repeated forms, each of which in istelf has a number of repeated items, the number of items being watched each time $digest runs causes the site to slow down. A good way to check this would be the batarang plugin for Chrome, which will show digest time in real-time. But it is kind of hard to pinpoint the issue as the OP can't show any code.
-
DNS almost 11 yearsThe OP does show the event timeline, and most of the shown activity is a long series of HTML parses. There may be a good reason why Angular is doing that versus creating them all in one fragment, but I think that's why it's slow here; the dirty-checking doesn't seem to be a big contributor.
-
jssebastian almost 11 yearsI doubt that the html parsing above is happening inside the digest cycle, so this likely has nothing to do with $digest performance.
-
MW. almost 11 years@jssebastian - No, this could indeed be unrelated to the $digest time. As noted, if the OP want to investigate it, I would recommend the Batarang-plugin.
-
Bradley Weston about 10 yearsWhat would you use instead of ng-click and ng-repeat?
-
Rishul Matta almost 10 yearsuse javascript concepts of event capturing and bubbling to reduce ng-click and for ng-repeat use single binding property (newer versions of angular js)
-
TaylorMac over 9 yearsI wouldn't go against the grain unless you are having performance problems or know you will. Ex. If you don't use the built-in directives for events, if you want to update your models, you're stuck triggering .$digest() (which triggers dirty checking from the current scope downward) or worse $apply() (which triggers this from $rootScope), which is less efficient than using ng-click or others (which just registers another watcher for that scope).
-
TaylorMac over 9 yearsRemoving all filters from HTML defeats the purpose of using filters, you might as well use a service instead. If you keep simple operations in filters (what they're intended for) you won't incur any noticeable performance hits.
-
Matheus over 9 yearsWere you still getting the 2 way data-binding with this approach?
-
jssebastian about 8 years@matheus: yes, the contents of each widget still had two way binding. On the other hand, the list of widgets to display did not, it was generated by concatenating each individual widget's template.