{"id":50906,"date":"2017-08-29T16:58:29","date_gmt":"2017-08-29T11:28:29","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=50906"},"modified":"2017-09-12T12:42:18","modified_gmt":"2017-09-12T07:12:18","slug":"angularjs-performance-tuning-in-enterprise-applications","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/angularjs-performance-tuning-in-enterprise-applications\/","title":{"rendered":"AngularJS Performance Tuning in Enterprise Applications"},"content":{"rendered":"<h2><strong>Introduction<\/strong><\/h2>\n<p>Before developing any application, it is always important to use the <a title=\"Our Technology Stack\" href=\"http:\/\/www.tothenew.com\/technologies\">technology stack<\/a> in a beneficial way. Using a technology doesn\u2019t count until and unless we use it effectively.<\/p>\n<p>Let\u2019s see some of\u00a0the common performance\u00a0issues\u00a0caused by AngularJS\u00a0and their possible suggestions to\u00a0fix or ways to avoid them.<\/p>\n<h2>Problem Faced or What Went Wrong During Implementation of Good Practices<\/h2>\n<p>From my past learnings and while <a title=\"AngularJS Development\" href=\"http:\/\/www.tothenew.com\/front-end-angularjs-development\">working on AngularJS<\/a> projects, I came to know few lags which I was making. This blog cover certain performance issues and possible suggestions to fix them.<\/p>\n<h2>Problem Area 1: parseHTML<\/h2>\n<p>The style and layout changes are applied by the browser in small batches. When batching is not possible, lagging is caused.<\/p>\n<p>Too many DOM operations are costly.<\/p>\n<h2>Possible Solution Area 1: parseHTML<\/h2>\n<ul>\n<li>We must write inline templates in directive\u2019s template property.<\/li>\n<li>Angular\u2019s built-in $templateCache must be prefilled with our own templates. Whenever we need an external template, the cache is checked by angular. Many grunt tasks automatically combines and minifies the HTML templates and prefills the AngularJS $templateCache<\/li>\n<\/ul>\n<h2>Problem Area 2: Slow dirty checking<\/h2>\n<p>There are two things in Dirty Checking:<\/p>\n<ol>\n<li>Recognizing changes<\/li>\n<li>Reacting to changes<\/li>\n<\/ol>\n<p>We register too many watchers and the <strong>complexity of values<\/strong> being watched is high, hence recognizing changes can be prolonged. Also, we do too much <strong>in watch operation<\/strong> that reacting to changes can be very slow.<\/p>\n<h2>Possible Solution Area 2: Slow dirty checking<\/h2>\n<ul>\n<li>Use unregister function to unregister all the watches after using the watcher:<br \/>\nvar unregisterFunction = $scope.$watch(\u2018namehere\u2019, function(){expression});<br \/>\nunregisterFunction ();<\/li>\n<li>$watch function with 2 parameters is fast. A 3rd parameter to $watch is also supported by Angular: $watch(&#8216;val&#8217;, function(){}, true). This 3rd parameter lets Angular perform deep checking, i.e checking each and every property of the object. This could be much more expensive hence causing performance issue.<\/li>\n<li>To solve this issue, $watchCollection(&#8216;val&#8217;, function(){}) is added by Angular. This method is almost similar to $watch with 3 parameters, except that it checks only the first layer of object\u2019s properties. This improves the performance to a great extent.<\/li>\n<li>Use isolated scopes in directives and pass only necessary values\/models.<br \/>\nRecalculate and cache complex model changes and apply them to watch expression.<\/li>\n<li>Pre-filter large collections and use the result as a source for ng-repeat. Only deep-watch if required. Deep-watching uses angular.\u00a0Equals on each property.<\/li>\n<\/ul>\n<h2>Problem Area 3: \u00a0Many DOM operations<\/h2>\n<p>Accessing the DOM is expensive-<\/p>\n<pre style=\"padding-left: 60px;\">angular.element('div.elementClass')<\/pre>\n<p>Therefore, one should work using as few DOM nodes as possible.<\/p>\n<p>For further reading, please see-<\/p>\n<p>Mastering Web Application Development with AngularJS Chapter 11<\/p>\n<h2>Possible Solution Area 3: Many DOM operations<\/h2>\n<ul>\n<li>Wherever possible, keep the DOM tree small.<\/li>\n<li>If possible, avoid DOM modification and do not set inline styles.<\/li>\n<li>Use ng-if instead of ng-show\/ng-hide.<\/li>\n<\/ul>\n<p>The\u00a0ng-show\u00a0directive toggles <a href=\"http:\/\/www.tothenew.com\/blog\/10-best-practices-in-css\/\">CSS display property<\/a> on an element, whereas the\u00a0ng-if\u00a0directive removes the element from DOM and reconstructs it if required.<\/p>\n<p>ng-show\/ng-hide-<\/p>\n<pre style=\"padding-left: 60px;\">&lt;span ng-show='Age==18`&gt;&lt;\/span&gt;\r\n&lt;span ng-hide='Age&lt;18`&gt;&lt;\/span&gt;<\/pre>\n<p>ng-if-<\/p>\n<pre style=\"padding-left: 60px;\">&lt;span ng-if=\u2019Age==18`&gt; &lt;\/span&gt;<\/pre>\n<h2>Problem Area 4: Code Duplication<\/h2>\n<p>For similar functionalities, we are in the habit of copy &amp; paste the code.<\/p>\n<h2>Possible Solution Area 4: Code Duplication<\/h2>\n<ul>\n<li>Use custom directives<\/li>\n<\/ul>\n<p>With Directives, we can create custom HTML tags, classes or attributes to execute required functionality on an HTML section. Then it becomes a reusable and independent component which can be embedded in HTML pages.<\/p>\n<pre style=\"padding-left: 60px;\">myApp.directive(\u2018myDirective\u2019, function() {\r\n return {\r\n  restrict: \u2018E\u2019,\r\n  template: \u2018&lt;h1&gt;I made a directive!&lt;\/h1&gt;\u2019\r\n };\r\n});\r\n&lt;body ng-app=\u201cmyApp\u201d&gt;\r\n &lt;my-directive&gt;&lt;\/my-directive&gt;\r\n&lt;\/body&gt;\r\n\r\n<\/pre>\n<p>For further reading, please see-<\/p>\n<p>https:\/\/dzone.com\/articles\/angularjs-10-best-practices<\/p>\n<ul>\n<li>There should be unique responsibilities for each task in a controller.<\/li>\n<\/ul>\n<p>Standard code should be written up to a level that no if -else is required in case of any modification required in a module<\/p>\n<h2>Problem Area 5: Memory Leaks in Angular<\/h2>\n<p>Whenever we have a reference in a child scope to a higher node, a reference is maintained and all the subtrees are kept alive. This creates a memory leak. If we register a listener on a service or on a DOM node that is not being deleted, it creates a risk of memory leaks.<\/p>\n<p>Memory leaks lead to performance problems as it slows down the applications and can cause process termination. In large applications, this is not at all good.<\/p>\n<p>The most common reason for the memory leak in Angular is jQuery usage in the directives. When we attach an event-listener in the directive using a jQuery plugin, it keeps a reference to DOM even if Angular deletes its own reference to the DOM. This means that it would never be garbage-collected by the browser, i.e., \u201c<strong>Detached DOM tree<\/strong>\u201d in the memory.<\/p>\n<h2>Possible Solution Area 5: Memory Leaks in Angular<\/h2>\n<ul>\n<li>Remove bindings to avoid memory leaks.<\/li>\n<\/ul>\n<p>Always unbind the jQuery event in the directive. Use $destroy method to clean up DOM bindings before removing an element from the DOM.<\/p>\n<pre style=\"padding-left: 60px;\">$scope.$on(\"$destroy\",function() {\r\n $(window).off(\"resize.Viewport\");\r\n});<\/pre>\n<ul>\n<li>Always cancel $timeout timers in $destroy Events.<\/li>\n<\/ul>\n<pre style=\"padding-left: 60px;\">$scope.$on(\"$destroy\",function(event) {\r\n $timeout.cancel(timer);\r\n});<\/pre>\n<h2>Other Workable Solutions<\/h2>\n<ul>\n<li>Avoid filter on ng-repeat-<\/li>\n<\/ul>\n<p>Filters are very easy to use- insert a pipe, the filter name and it\u2019s done. However, Angular runs every filter\u00a0<em>2 times<\/em>\u00a0per\u00a0$digest\u00a0cycle. Once whenever anything changes and another time to collect other changes. They do not really remove the collection from memory, instead only mask filtered items with CSS. This leads to heavy lifting.<\/p>\n<p>Instead of using a filter in ng-repeat &#8211;<\/p>\n<pre style=\"padding-left: 60px;\">&lt;ul&gt;\r\n &lt;li ng-repeat=\u201ddata in bookData | filter:\u2019A\u2019\u201d&gt;{{ data }}&lt;\/li&gt;\r\n&lt;\/ul&gt;<\/pre>\n<p>Use the $filter service in controller-<\/p>\n<p>$filter\u00a0provider should be used to run filters before parsing into the DOM. This pre processes the data before sending it to View, which saves the parsing of the DOM and knowing the inline filter syntax.<\/p>\n<p>\/\/ controller<\/p>\n<pre style=\"padding-left: 60px;\">$scope.filteredWords = $filter('filter')($scope,bookData,\u00a0 'A');<\/pre>\n<p>\/\/ HTML<\/p>\n<pre style=\"padding-left: 60px;\">&lt;ul&gt;\r\n &lt;li ng-repeat=\u201ddata in filteredWords\u201d&gt;{{ data }}&lt;\/li&gt;\r\n&lt;\/ul&gt;<\/pre>\n<ul>\n<li>Use pagination or infinite scrolling for lists (with ng-repeat).<\/li>\n<\/ul>\n<p>Infinite scroll is a separate module of angular that you can use to implement infinite scrolling in\u00a0AngularJS applications.<\/p>\n<pre style=\"padding-left: 60px;\">&lt;div ng-app='myApp' ng-controller='MyController'&gt;\r\n &lt;div infinite-scroll='loadMore()' infinite-scroll-distance='2'&gt;\r\n  &lt;img ng-repeat='img in images' ng- src='http:\/\/placehold.it\/225x250&amp;text={{img}}'&gt;\r\n &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n\r\nvar myApp = angular.module('myApp', ['infinite-scroll']);\r\nmyApp.controller('MyController', function($scope) {\r\n $scope.images = [1, 2, 3, 4, 5, 6, 7, 8];\r\n $scope.loadMore = function() {\r\n  var last = $scope.images[$scope.images.length - 1];\r\n  for(var i = 1; i &lt;= 8; i++) {\r\n   $scope.images.push(last + i);\r\n  }\r\n };\r\n});<\/pre>\n<h2>Benefits<\/h2>\n<h2>Quantitative Benefits<\/h2>\n<p>Performance optimizations always bear the risk of increasing code complexity and therefore decreasing maintainability, by optimization we will be making <a href=\"http:\/\/www.tothenew.com\/blog\/building-intuitive-frontend-interfaces-with-angularjs\/\" target=\"_blank\">AngularJS as a primary choice for development<\/a>.<\/p>\n<p>It encourages an individual to deal with models not only on the server side but also on the client side.\u00a0Angular JS enables you to create software more quickly and with less effort. It has a 2-way data-binding, so saving it to the server now takes a smaller number of lines, unlike jQuery that requires creating your own object, and several different click and event handlers.<\/p>\n<p>The Dependency injection and the ability to create directives in AngularJS has really excited the developer community. These features let developers create and share components very easily.<\/p>\n<h2>Qualitative Benefits<\/h2>\n<p>Angular is next generation framework where every tool was designed to work with all other tools in an interconnected manner. It is not merely bundling of existing tools, but the plugins are designed sophisticatedly to meet the purpose of each tool used.<\/p>\n<p>1.) Data models in Angular are plain old JavaScript objects (POJO) which do not need irrelevant setter and getter functions. One can add and change properties directly on it and loop over objects and arrays. Due to this, the code looks more intuitive and much cleaner.<\/p>\n<p>2.) Improve the testability of the software <strong>&#8211;<\/strong> AngularJS has dependency injection at its core, which makes it easy to test.\u00a0 Even the documentation on the site of the portal has testing as a part of every tutorial step, which almost makes it hard NOT to test.<\/p>\n<p>3.) This allows us to keep in mind the same object-oriented design principles that in general makes the software more maintainable compared to procedural which results in a software that is more maintainable.<\/p>\n<h2>Learning\/ Improvements<\/h2>\n<p>Main application module should be in the root client directory. A module should not be altered apart from the one where it is defined because a module should be reliable if anyone wants to include it as a reusable component.<\/p>\n<p>When writing web applications, we have objects at server-side that at times aren\u2019t represented as objects at the client-side.\u00a0 This might be OK for simple sites, but if it gets complicated, it can be an immense help to mirror these objects on both sides.<\/p>\n<p>It gives elasticity with filters. Filters filter the data before reaching the view and can include something as simple as reversing the order of an array, formatting decimal places on a number, implementing pagination or filtering an array based on a parameter.<\/p>\n<p>In applications like jQuery etc., the view presents\u00a0data by modifying the DOM and adds behavior by manipulating it. With Angular, code for DOM manipulation must be inside directives and not inside view. Angular looks at the view just like any other HTML page with placeholders for data. This pairs perfectly with UI designers.<\/p>\n<h2>Applicability to Other Projects<\/h2>\n<p>Projects that are using AngularJS for the development of UI will meet these scenarios, by keeping our model clean and minimum number of watchers we will be able to optimize the performance with great ease. All the mentioned problems\/solutions are applicable for any kind of AngularJS project and are handy for getting things done in one go.<\/p>\n<h2>References<\/h2>\n<p><a href=\"https:\/\/angularjs.org\/\">https:\/\/angularjs.org<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Before developing any application, it is always important to use the technology stack in a beneficial way. Using a technology doesn\u2019t count until and unless we use it effectively. Let\u2019s see some of\u00a0the common performance\u00a0issues\u00a0caused by AngularJS\u00a0and their possible suggestions to\u00a0fix or ways to avoid them. Problem Faced or What Went Wrong During Implementation [&hellip;]<\/p>\n","protected":false},"author":1018,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":3},"categories":[1439,3429,3917,1994,1],"tags":[3955,955,4697,4860,4842,55,4230],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/50906"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1018"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=50906"}],"version-history":[{"count":15,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/50906\/revisions"}],"predecessor-version":[{"id":51790,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/50906\/revisions\/51790"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=50906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=50906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=50906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}