![]()
What You’ll Learn
Why unnecessary re-renders happen in AngularJS
How to optimize performance by reducing digest cycles
Best practices to minimize re-renders
1️⃣ Understanding Re-Renders in AngularJS
How Rendering Works in AngularJS?
AngularJS uses the digest cycle to detect changes and update the UI.
- Every time an event occurs (e.g., API call, user input, timeout), AngularJS checks all bindings and watchers.
- If there are many watchers, the digest cycle slows down, causing laggy performance.
Why Do Unnecessary Re-Renders Happen?
1️⃣ Too many watchers ($watch, $watchCollection)
2️⃣ Using two-way data binding (ng-model) excessively
3️⃣ Frequent digest cycle triggers ($timeout, $interval, $http)
4️⃣ Unoptimized ng-repeat (large lists)
5️⃣ Not using track by in ng-repeat
6️⃣ Modifying objects inside a digest cycle
2️⃣ Best Practices to Minimize Re-Renders
1. Use One-Time Binding (::)
If data does not change, use one-time binding to remove unnecessary watchers.
<h1>{{ ::user.name }}</h1>
<p>{{ ::user.age }}</p>
This ensures user.name and user.age are evaluated only once.
2. Use track by in ng-repeat
If ng-repeat re-renders too often, AngularJS loses track of items. Use track by to prevent unnecessary re-rendering.
<li ng-repeat="item in items track by item.id">{{ item.name }}</li>
Improves performance by preventing unnecessary DOM updates.
3. Use $watchCollection Instead of $watch for Arrays
If watching arrays, use $watchCollection instead of $watch.
$scope.$watchCollection("items", function(newVal, oldVal) {
console.log("Items changed!");
});
This only watches array length and item changes instead of deep-watching every object property.
4. Use bindOnce in Directives
If a directive displays static content, use bindOnce to prevent re-evaluation.
app.directive("staticInfo", function() {
return {
scope: { data: "=" },
template: "<p>{{ ::data.info }}</p>"
};
});
Prevents unnecessary updates in the directive’s scope.
5. Reduce $digest Scope with $applyAsync
Using $apply() triggers an immediate digest cycle, which is costly. Instead, use $applyAsync(), which batches updates.
$scope.$applyAsync(function() {
$scope.data = newData;
});
Reduces the number of digest cycles.
6. Avoid Unnecessary $http Digest Cycles
If you use $http, disable automatic digest cycles using cache: true or $httpProvider.
app.config(function($httpProvider) {
$httpProvider.useApplyAsync(true);
});
This batches multiple HTTP responses into a single digest cycle.
7. Use bind-once for Large Lists (3rd-Party Solution)
For large lists, use a third-party directive like bindonce.
<li bindonce ng-repeat="item in items">
<span bo-text="item.name"></span>
</li>
Reduces watchers count and improves performance.
8. Optimize ng-show and ng-hide
Problem: ng-show and ng-hide keep elements in the DOM, leading to unnecessary digest cycles.
Solution: Use ng-if instead.
<!-- Bad: Still exists in the DOM -->
<p ng-show="isVisible">Visible text</p>
<!-- Good: Removed from DOM when false -->
<p ng-if="isVisible">Visible text</p>
ng-if removes the element from the DOM, reducing watchers.
3️⃣ When to Use These Optimizations?
| Scenario | Optimization to Apply |
|---|---|
| Static Data | Use :: (one-time binding) |
| Large Lists | Use track by in ng-repeat |
| Watching Arrays | Use $watchCollection |
| Heavy Directives | Use bindOnce |
| Frequent API Calls | Use $httpProvider.useApplyAsync(true) |
| DOM Performance | Prefer ng-if over ng-show |
