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.
Optimizing Angular
Performance
Morgan Stone
@morganstone
Render Time
Tools: ng-stats
STRATEGY:
Minimize/Avoid
Watchers
$watch
scope.$watch('name', function(newValue, oldValue) {
scope.counter = scope.counter + 1;
});
where watches are set
$scope.$watch
{{ }} type bindings (ng-bind too)
Most directives (i.e. ng-show)
Scope variables scope...
digest cycle runs on
User action (ng-click etc). Most built in directives will call $scope.apply upon
completion which tri...
ng-if instead of ng-show
<div class="panel" ng-show="panel.isOpen" ng-repeat="panel in panels">
{{panel.name}}
<div class=...
ng-if instead of ng-show
<div class="panel" ng-show="panel.isOpen" ng-repeat="panel in panels">
{{panel.name}}
<div class=...
ng-if instead of ng-show
<div class="panel" ng-if="panel.isOpen" ng-repeat="panel in panels">
{{panel.name}}
<div class="c...
Bind once
<p>
{{ vm.user }}
</p>
Bind once
<p>
{{ ::vm.user }}
</p>
Once the value is defined,
Angular will render it and
unbind it from the watchers
STRATEGY:
Reduce digest cycle time
track by
<div ng-repeat="model in collection | orderBy: 'id' as
filtered_result">
{{model.name}}
</div>
http://blog.500tech.com/is-reactjs-fast/
Original:
http://speed.examples.500tech.com/ngrepeat/before/angular.html
Adding track by
http://speed.examples.500tech.com...
track by
<div ng-repeat="model in collection | orderBy: 'id' as
filtered_result">
{{model.name}}
</div>
Without track by n...
track by
<div ng-repeat="model in collection | orderBy: 'id' as
filtered_result track by model.id">
{{model.name}}
</div>
...
track by
<div ng-repeat="model in collection | orderBy: 'id' as
filtered_result track by model.id">
{{model.name}}
</div>
...
track by
<div ng-repeat="model in collection | orderBy: 'id' as
filtered_result track by $index">
{{model.name}}
</div>
tr...
piped | filters
ng-repeat=”person in listOfFriends | filter:{
available: true}”
{{ person.birthday | date }}
Angular runs every
single piped filter twice
per $digest cycle
<div class="list-group">
<div
class="list-group-item"
ng-repeat="person in listOfFriends | filter:{ available: true}">
<di...
<div class="list-group">
<div
class="list-group-item"
ng-repeat="person in listOfFriends | filter:{ available: true}">
<di...
Keep your controllers
small & leverage
services to do the
heavy lifting
angular
.module('app')
.factory('friendsService', friendsService);
friendsService.$inject = ['$http', '$filter'];
function...
getFriends: getFriends,
getAvailableFriends: getAvailableFriends
};
return factory;
function getFriends() {
return $http.g...
function successCallback(friends) {
return friends.map(function(friend) {
friend.birthday = $filter('date')(friend.birthda...
Load Time
STRATEGY:
Reduce # of requests
Caching
$http.get(url, { cache: true}).success(...);
angular.module('docsIsolateScopeDirective', []).directive('myCustomer',
function() {
return {
restrict: 'E',
scope: {
cust...
angular.module('docsIsolateScopeDirective', []).directive('myCustomer',
function() {
return {
restrict: 'E',
scope: {
cust...
ui.router
angular.module('abcApp', ['ui.router']).config(function ($stateProvider) {
$stateProvider
.state('user.add', {
u...
<div class="slide-animate" ng-include="template.url"></div>
which may trigger
another request
Even though template
requests are cached after
GET, they really start to
add up, especially on the
initial load of the app
<script
type="text/ng-template"
id="templateId.html">
<p>This is the content of the template</p>
</script>
You could do th...
var myApp = angular.module('myApp', []);
myApp.run(function($templateCache) {
$templateCache.put('templateId.html', 'This ...
Sorry gramps
But we’re gonna
Javascript our HTMLs
in the BUILD.
Standard Angular build process
Concat & minify all Javascript files into a single file
Combine and minify CSS files into a...
Standard Angular build process
Concat & minify all Javascript files into a single file
Combine and minify CSS files into a...
ngHtml2JS
var ngHtml2Js = require('gulp-ng-html2js');
var gulpConcat = require('gulp-concat');
gulp.task('createTemplates'...
ngHtml2JS
angular.module("app").run(["$templateCache", function ($templateCache) {
$templateCache.put("template/modal/back...
Thank you
mstone@designbymorgan.com
@morganstone
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
Upcoming SlideShare
Loading in …5
×

Optimizing Angular Performance in Enterprise Single Page Apps

282 views

Published on

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/

Published in: Technology
  • Be the first to comment

  • Be the first to like this

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

×