Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular JS Scaling & Performance

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:

Recalculate StyleGC Event

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.

like image 535
trevorewen Avatar asked Jul 15 '13 14:07

trevorewen


4 Answers

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 :)

like image 56
btm1 Avatar answered Nov 14 '22 01:11

btm1


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.

like image 8
jssebastian Avatar answered Nov 14 '22 02:11

jssebastian


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

like image 6
Abbasi Avatar answered Nov 14 '22 02:11

Abbasi


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

like image 3
MW. Avatar answered Nov 14 '22 00:11

MW.