Today I had to fix a performance issue caused by this code: Pay attention to updateStats called inside the template
<script type="text/ng-template" id="entityGrouper">
<section>
<div>
<ul ng-click="hideEntityBox = !hideEntityBox">
<li>
{{ entityNode.name }}
</li>
<li ng-repeat="breadcrumbItem in entityNode.breadcrumb">
{{ breadcrumbItem }}
</li>
</ul>
{{ updateStats(entityNode) }}
<span ng-include="'/mypath/views/resume.html'"></span>
</div>
<div>
<div ng-repeat="entityNode in entityNode.group" ng-include="'entityGrouper'"></div>
<div ng-repeat="entity in entityNode.group" ng-include="'entityBox'"></div>
</section>
</script>
Template use:
<div ng-repeat="entityNode in entityNode.group" ng-include="'entityGrouper'"></div>
After debugging this code I discovered that this function was called many more time than the array size (my array has 4 objects and the function was called more than 100 times), even mouse hover called this function. I fixed that by just putting a ng-init inside the template and now it's working properly, but I didn't figure out why this function has been called so many times. Is there something about two way data binding?
Today I had to fix a performance issue caused by this code: Pay attention to updateStats called inside the template
<script type="text/ng-template" id="entityGrouper">
<section>
<div>
<ul ng-click="hideEntityBox = !hideEntityBox">
<li>
{{ entityNode.name }}
</li>
<li ng-repeat="breadcrumbItem in entityNode.breadcrumb">
{{ breadcrumbItem }}
</li>
</ul>
{{ updateStats(entityNode) }}
<span ng-include="'/mypath/views/resume.html'"></span>
</div>
<div>
<div ng-repeat="entityNode in entityNode.group" ng-include="'entityGrouper'"></div>
<div ng-repeat="entity in entityNode.group" ng-include="'entityBox'"></div>
</section>
</script>
Template use:
<div ng-repeat="entityNode in entityNode.group" ng-include="'entityGrouper'"></div>
After debugging this code I discovered that this function was called many more time than the array size (my array has 4 objects and the function was called more than 100 times), even mouse hover called this function. I fixed that by just putting a ng-init inside the template and now it's working properly, but I didn't figure out why this function has been called so many times. Is there something about two way data binding?
Share Improve this question edited Nov 25, 2016 at 17:56 thiagoh 7,3888 gold badges54 silver badges78 bronze badges asked Jan 26, 2016 at 20:37 Victor LaerteVictor Laerte 6,55614 gold badges58 silver badges105 bronze badges 1-
Are you recursively calling the same template? there is again a
<div ng-repeat="entityNode in entityNode.group" ng-include="'entityGrouper'"></div>
call made inside the template – Developer Commented Nov 24, 2016 at 17:39
3 Answers
Reset to default 7It is usually remended to use a $watch
for scenarios like this. Since you are binding a function {{updateStats()}}
, it will execute on every digest cycle.
So in your code whenever a digest cycle is called, it will also call the function. And digest cycles are frequently called internally in Angular.
This is happening not because of two-way data binding (it is applicable to form inputs), but rather because of angular change detection. Angular periodically checks if any of the values, bound to a template, changed, and if so - updates its value in the view. Typically, it is triggered by user generated events. In order to check if the value of updateStats(entityNode)
changed, Angular evaluates it, which causes the performance hit.
To fix this, you may use previously mentioned one-time binding updateStats(entityNode)
if the result is set once and will never change in the future. I guess, this is your case, and you have already moved the evaluation to ng-init
. For values that update with time, it would be better to create a separate property in entityNode
like entityNode.stats
, display it in the template and run the updateStats(entityNode)
in your controller or service only when necessary. By doing that, you will prevent running updateStats(entityNode)
on each digest cycle (you have already seen how often that is) and thereby improve your app's performance.
What you are seeing is the result of a digest cycle.
Adding a ::
will call the function once / one-time binding.
{{ ::updateStats(entityNode) }}