Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: $eval takes much time

During profiling of my angularjs application, I found that sometimes $get.Scope.$eval takes more than 100ms. During the single $digest loop there are at least 3 long cases of $get.Scope.$eval and I'd like to optimize this part.

Below the $get.Scope.$eval in profiler I see only invoking of angularjs code.

Here is a screenshot of profile chart.

enter image description here

Could anyone suggest, what's going on and how to optimize this part? I suppose that it can be caused by ng-repeat, ng-include or ng-if, but I'm not sure.

Update: Here is the simplified structure of my application. Probably, the problem is in the architecture of my application. The app mostly working on the single route and change it only for 3 cases, so application store state in the global controller AppController - fat controller. Also there are 20k+ nodes in the html and the number can grow(maximum I saw is 60k)

like image 333
uladzimir Avatar asked Nov 10 '22 08:11

uladzimir


1 Answers

$eval is used internally by angular when resolving angular expressions, such as {{variable}}. Without seeing any of your code, it's hard to tell what expressions are using resources unnecessarily, but usually too large or nested ng-repeats (or many ng- directives included within an ng-repeat) are a code smell.

Angular uses dirty checking to evaluate these expressions (for lack of a better option) - that means that every time you create a binding with the {{}} syntax, it creates an implicit $watch expression getting that value, that will be called every digest cycle to see if the value has changed (on which change the relevant parts of the DOM are regenerated).

Here's one optimization I've used successfully in the past:

most of the time, when you bind a value with {{}}, you don't actually expect the value to change (like a label), and this 2-way data binding is completely superflous. Since angular version 1.3 you have the options to create one-time bindings with the :: syntax:

One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value

which eliminates the corresponding performance overhead of such bindings. (If you're using older angular versions, external libraries can mimick this behaviour, such as bindonce.)

Here are some additional tools I've found useful while profiling/optimizing angular apps:

  • Batarang, a chrome extension "for debugging and profiling angular applications"
  • This stackoverflow answer, giving a neat solution for counting how many watch expressions are active on your page. A rule of thumb is that if you're above 2000, you'll start noticing performance issues, and you should think about changing your architecture - employ lazy loading mechanisms, reconsider whether you truly need all the bindings etc.

  • In production environments disabling the default "debug mode" of angular can also help with performance.

like image 50
doldt Avatar answered Nov 15 '22 04:11

doldt