Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
Single Page Apps in Sitecore
Single Page Apps in Sitecore
Loading in …3
×
1 of 52

Optimizing Angular Performance in Enterprise Single Page Apps

0

Share

Download to read offline

Getting the most out of Angular 1.x in enterprise apps
Originally presented at the Birmingham Javascript Meetup on June 2, 2016
http://www.meetup.com/bhm-js/

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Optimizing Angular Performance in Enterprise Single Page Apps

  1. 1. Optimizing Angular Performance Morgan Stone @morganstone
  2. 2. Render Time
  3. 3. Tools: ng-stats
  4. 4. STRATEGY: Minimize/Avoid Watchers
  5. 5. $watch scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
  6. 6. where watches are set $scope.$watch {{ }} type bindings (ng-bind too) Most directives (i.e. ng-show) Scope variables scope: { bar: '='} Filters {{ value | myFilter }} ng-repeat http://www.alexkras.com/11-tips-to-improve-angularjs-performance/
  7. 7. digest cycle runs on User action (ng-click etc). Most built in directives will call $scope.apply upon completion which triggers the digest cycle. ng-change ng-model $http events (so all ajax calls) $q promises resolved $timeout $interval Manual call to $scope.apply and $scope.digest http://www.alexkras.com/11-tips-to-improve-angularjs-performance/
  8. 8. ng-if instead of ng-show <div class="panel" ng-show="panel.isOpen" ng-repeat="panel in panels"> {{panel.name}} <div class="checkbox" ng-repeat="setting in panel.settings"> <label> <input type="checkbox" ng-model="setting.on"/> {{setting.name}} </label> </div> </div>
  9. 9. ng-if instead of ng-show <div class="panel" ng-show="panel.isOpen" ng-repeat="panel in panels"> {{panel.name}} <div class="checkbox" ng-repeat="setting in panel.settings"> <label> <input type="checkbox" ng-model="setting.on"/> {{setting.name}} </label> </div> </div> With ng-show, the nodes remain in the DOM and are being watched
  10. 10. ng-if instead of ng-show <div class="panel" ng-if="panel.isOpen" ng-repeat="panel in panels"> {{panel.name}} <div class="checkbox" ng-repeat="setting in panel.settings"> <label> <input type="checkbox" ng-model="setting.on"/> {{setting.name}} </label> </div> </div> With ng-if, only nodes visible will be watched
  11. 11. Bind once <p> {{ vm.user }} </p>
  12. 12. Bind once <p> {{ ::vm.user }} </p> Once the value is defined, Angular will render it and unbind it from the watchers
  13. 13. STRATEGY: Reduce digest cycle time
  14. 14. track by <div ng-repeat="model in collection | orderBy: 'id' as filtered_result"> {{model.name}} </div>
  15. 15. http://blog.500tech.com/is-reactjs-fast/
  16. 16. Original: http://speed.examples.500tech.com/ngrepeat/before/angular.html Adding track by http://speed.examples.500tech.com/ngrepeat/after/angular.html
  17. 17. track by <div ng-repeat="model in collection | orderBy: 'id' as filtered_result"> {{model.name}} </div> Without track by ng-repeat rebuilds all the DOM nodes, including nodes that require no change
  18. 18. track by <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id"> {{model.name}} </div> track by provides an index Angular can use to track model changes
  19. 19. track by <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id"> {{model.name}} </div> track by must be last in the expression
  20. 20. track by <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by $index"> {{model.name}} </div> track by $index can also provide a performance boost
  21. 21. piped | filters ng-repeat=”person in listOfFriends | filter:{ available: true}” {{ person.birthday | date }}
  22. 22. Angular runs every single piped filter twice per $digest cycle
  23. 23. <div class="list-group"> <div class="list-group-item" ng-repeat="person in listOfFriends | filter:{ available: true}"> <div class="row"> <div class="col-sm-6"> {{person.name}} </div> <div class="col-sm-6"> {{person.birthday | date: 'shortDate' }} </div> </div> </div> </div>
  24. 24. <div class="list-group"> <div class="list-group-item" ng-repeat="person in listOfFriends | filter:{ available: true}"> <div class="row"> <div class="col-sm-6"> {{person.name}} </div> <div class="col-sm-6"> {{person.birthday | date: 'shortDate' }} </div> </div> </div> </div> Could be done in controller or better yet a service
  25. 25. Keep your controllers small & leverage services to do the heavy lifting
  26. 26. angular .module('app') .factory('friendsService', friendsService); friendsService.$inject = ['$http', '$filter']; function friendsService($http, $filter) { var factory = { getFriends: getFriends, getAvailableFriends: getAvailableFriends }; return factory; function getFriends() { return $http.get('/someUrl', config) Injecting $filter
  27. 27. getFriends: getFriends, getAvailableFriends: getAvailableFriends }; return factory; function getFriends() { return $http.get('/someUrl', config) .then(successCallback); function successCallback(friends) { return friends.map(function(friend) { friend.birthday = $filter('date')(friend.birthday, 'shortDate'); return friend; }); } } Filter it one place… in the service
  28. 28. function successCallback(friends) { return friends.map(function(friend) { friend.birthday = $filter('date')(friend.birthday, 'shortDate'); return friend; }); } } function getAvailableFriends() { return getFriends.then(function(friends) { return friends.filter(function(friend) { return friend.available; }); }) } } Create additional methods for common ng-repeat | filters
  29. 29. Load Time
  30. 30. STRATEGY: Reduce # of requests
  31. 31. Caching $http.get(url, { cache: true}).success(...);
  32. 32. angular.module('docsIsolateScopeDirective', []).directive('myCustomer', function() { return { restrict: 'E', scope: { customerInfo: '=info' }, templateUrl: 'my-customer-iso.html' }; });
  33. 33. angular.module('docsIsolateScopeDirective', []).directive('myCustomer', function() { return { restrict: 'E', scope: { customerInfo: '=info' }, templateUrl: 'my-customer-iso.html' }; }); Each directive templateUrl results in another request
  34. 34. ui.router angular.module('abcApp', ['ui.router']).config(function ($stateProvider) { $stateProvider .state('user.add', { url: '/mgt/user/add', templateUrl: 'views/mgt_user/add.html' }) .state('user.view', { url: '/mgt/user/view/:userId', templateUrl: 'views/mgt_user/view.html' }) .state('user.list', { url: '/mgt/user/list', templateUrl: 'views/mgt_user/list.html' }); }); and maybe another request
  35. 35. <div class="slide-animate" ng-include="template.url"></div> which may trigger another request
  36. 36. Even though template requests are cached after GET, they really start to add up, especially on the initial load of the app
  37. 37. <script type="text/ng-template" id="templateId.html"> <p>This is the content of the template</p> </script> You could do this... But this is ugly and unmaintainable
  38. 38. var myApp = angular.module('myApp', []); myApp.run(function($templateCache) { $templateCache.put('templateId.html', 'This is the content of the template'); }); $templateCache
  39. 39. Sorry gramps But we’re gonna Javascript our HTMLs in the BUILD.
  40. 40. Standard Angular build process Concat & minify all Javascript files into a single file Combine and minify CSS files into a single file Gzip & cache assets
  41. 41. Standard Angular build process Concat & minify all Javascript files into a single file Combine and minify CSS files into a single file Gzip & cache assets Store HTML files into $templateCache
  42. 42. ngHtml2JS var ngHtml2Js = require('gulp-ng-html2js'); var gulpConcat = require('gulp-concat'); gulp.task('createTemplates', function(cb){ gulp.src(['/app/**/*.html', '/app/**/*.svg']) .pipe(ngHtml2Js({ base: '/', moduleName: 'app', prefix: '/' })) .pipe(gulpConcat('templates.')) .pipe(gulp.dest('./services')) .on('end', cb); });
  43. 43. ngHtml2JS angular.module("app").run(["$templateCache", function ($templateCache) { $templateCache.put("template/modal/backdrop.html", "<div class="modal-backdrop fade"n" + " ng-class="{in: animate}"n" + " ng-style="{'z-index': 1040 + (index && 1 || 0) + index*10}"n" + "></div>n" + ""); }]);
  44. 44. Thank you mstone@designbymorgan.com @morganstone

×