AngularJS Performance Optimization techniques

Loading

AngularJS is a powerful framework for building dynamic web applications, but as applications grow, performance can become an issue. Optimizing AngularJS applications ensures smooth user experiences and efficient resource utilization. This guide covers best practices for enhancing AngularJS performance.


1. Minimize Watchers and Digest Cycle

1.1 Understanding Watchers

AngularJS uses the $digest cycle to detect changes in the application by checking all watchers. More watchers lead to longer digest cycles and slow performance.

1.2 How to Optimize Watchers

  • Use one-time bindings (::) for static data: <h1>{{::title}}</h1>
  • Avoid unnecessary ng-repeat expressions.
  • Reduce the number of bound DOM elements.
  • Use $scope.$watch sparingly.

2. Optimize ng-repeat

2.1 Use track by for ng-repeat

When using ng-repeat, AngularJS creates and destroys elements frequently, impacting performance. Using track by helps Angular track elements efficiently.

<li ng-repeat="item in items track by item.id">{{ item.name }}</li>

2.2 Use Limitations on Large Data

For large datasets, consider paginating or limiting the number of displayed items.

<li ng-repeat="item in items | limitTo:10">{{ item.name }}</li>

3. Reduce DOM Manipulations

3.1 Use ng-if Instead of ng-show/ng-hide

ng-show and ng-hide keep elements in the DOM, whereas ng-if removes them when not needed.

<!-- Inefficient -->
<div ng-show="isVisible">Visible Element</div>

<!-- Efficient -->
<div ng-if="isVisible">Visible Element</div>

3.2 Use $compile Wisely

Manually compiling templates can slow down performance if overused. Avoid using $compile inside loops.


4. Optimize Scope Usage

4.1 Avoid Deep Watchers

AngularJS deep-watches objects, making the digest cycle slower. Use shallow watchers where possible.

$scope.$watch('user', function(newVal, oldVal) {
// Avoid deep watching
}, true);

Instead, watch specific properties:

$scope.$watch('user.name', function(newVal, oldVal) {
// More efficient
});

4.2 Unbind Watchers When Not Needed

Remove watchers when they are no longer needed using $destroy.

var unwatch = $scope.$watch('someProperty', function(newVal, oldVal) {
console.log(newVal);
});

// Unbind when done
$scope.$on('$destroy', function() {
unwatch();
});

5. Lazy Load Modules and Components

5.1 Load Dependencies on Demand

Use lazy loading for controllers and modules to avoid loading everything at once.

var app = angular.module("myApp", ["oc.lazyLoad"]);

app.config(["$ocLazyLoadProvider", function($ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
debug: true
});
}]);

app.controller("MainController", function($scope, $ocLazyLoad) {
$scope.loadModule = function() {
$ocLazyLoad.load("someModule.js");
};
});

6. Use Bind Once (::) for Static Data

For data that does not change, use one-time bindings:

<h1>{{::title}}</h1>

This prevents Angular from re-evaluating the expression during the digest cycle.


7. Optimize API Calls and Data Binding

7.1 Use Service Instead of $scope for Data Storage

If data is used in multiple controllers, use a service instead of $scope variables.

app.service("DataService", function() {
var data = {};
return {
getData: function() { return data; },
setData: function(newData) { data = newData; }
};
});

7.2 Use $http with Caching

Enable caching for repeated API calls:

app.service("ApiService", function($http) {
this.getData = function() {
return $http.get("https://api.example.com/data", { cache: true });
};
});

7.3 Debounce API Calls

If making frequent API calls, use debounce techniques:

app.controller("SearchController", function($scope, $timeout) {
var timeout = null;

$scope.search = function(query) {
if (timeout) $timeout.cancel(timeout);
timeout = $timeout(function() {
// Make API call here
console.log("Fetching data for", query);
}, 300);
};
});

8. Optimize Images and Assets

  • Use lazy loading for images.
  • Optimize image sizes using tools like TinyPNG.
  • Use CDN for static assets.
<img data-src="image.jpg" class="lazyload">

Use libraries like LazyLoad.js to load images only when they appear in the viewport.


9. Use AngularJS Batching

Batch multiple updates inside $applyAsync to prevent multiple digest cycles.

$scope.$applyAsync(function() {
$scope.data = newData;
});

10. Enable Performance Debugging

Use AngularJS Batarang (Chrome Extension) to analyze watchers and performance bottlenecks.

Run this in the browser console to check the number of watchers:

(function() {
var root = angular.element(document.getElementsByTagName("body"));
var watchers = [];

var f = function(element) {
angular.forEach(["$scope", "$isolateScope"], function(scopeProperty) {
if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function(watcher) {
watchers.push(watcher);
});
}
});

angular.forEach(element.children(), function(childElement) {
f(angular.element(childElement));
});
};

f(root);
console.log("Total Watchers: ", watchers.length);
})();

Leave a Reply

Your email address will not be published. Required fields are marked *