AngularJS.
Performance &
Limits.
Dragos Rusu - CodeCamp Iasi 2014
(dragos.rusu@bytex.ro)
Our story
From
"We have to rethink this whole module, remove time navigation... it's just too sluggish." ★
to
"It's awesom...
A few words about me
Dragos Rusu @ SOFTVISION
WEB/ZEND ENGINEER since 2007 (backend, frontend)
ARTICLE WRITER (PHP Archite...
We will discuss about...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
...
disclaimer
PERFORMANCE principles for heavy apps (+500 man days)
* many items are not covered here.
* code samples - only ...
Shall we?
1. View watches / data bindings
GENERAL CONTEXT
"more of 2000 watchers can lag the UI" (angular-tips.com)
"the expressions in curly braces denote bindings...
Ok... but why would I be counting watches?
Every watcher is run at the digest cycle. The digest cycle is repeated until none of the results has
changed value
(Brian ...
✈ A peak into AngularJS source code
$apply:function(expr){
try{
beginPhase('$apply');
returnthis.$eval(expr);
}catch(e){$e...
(1) double-binding creates tons of listeners
SOLUTION:
Whenever feasible, use single-binding solutions
double binding DEMO / bindonce DEMO
Why? Is double-binding slow?
Not quite. The AngularJS way of implementing it is slow ($dirty flags instead of observable
p...
github.com/Pasvaz/bindonce
github.com/kseamon/fast-bind
pssst: bindonce will be part of AngularJS 1.3 release!
(2) direct function calls from templates are called very often
SOLUTION: pre-compute the values to shown in the view model...
EXAMPLE
vatTotal will be recomputed on each scope $digest, regardless if the values that vatTotal() depend on
are changed ...
(3) iterating over large data sets slows down the page
SOLUTION: create a lightweight iterable view model
angular.module('...
(4) ng-repeat extra DOM manipulations
SOLUTION: ng-repeat with track by id (DEMO)
<ul>
<ling-repeat="iteminitemstrackbyite...
(5) filters are called very often
SOLUTION: lightweight quasi-independent filters
<span>{{value}}</span>
<ul>
<ling-repeat...
(6) multiple recursive $watch might cause page flickering
SOLUTION: try to avoid recursive watch, where feasible
$scope.$w...
(7) direct DOM watch functions might slow down the page
SOLUTION: try to avoid complex valueExpression, where feasible (us...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
2. What you see is what you show
ng-if vs. ng-show (1)
ng-hide and ng-show makes no speed difference (DEMO)
<ulng-hide="hideCondition">
<ling-repeat="itemi...
ng-if vs. ng-show (2)
ng-if/ng-switch might make a difference on more content
(e.g. tabbed page)
<ulng-if="displayConditio...
remove non-visible elements in the scroll (1)
one easy way would be PAGINATION
doesn't always apply though...
remove non-visible elements in the scroll (2)
DISPLAY elements, but ONLY THE VISIBLE ones
known as the VIRTUAL/INFINITE SC...
remove non-visible elements in the scroll (3)
usually occurs when large data sets need to be displayed
OpenSource solution...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
3. The risk of polluting scopes
✈ DOM / SCOPES
(1) relying on multiple $rootScope and appCtrl functions may slow down the $digest
SOLUTION: try to avoid polluting $rootS...
... and have some privacy in all scopes
angular.module('codecamp').controller('testCtrl',[
'$scope',function($scope){
'use...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
4. Core directives to avoid
ALL of them
... right
Remember what we've said earlier?
"more of 2000 watchers can lag the UI" (angular-tips.com)
varngEventDirectives={};forEach(
'clickdblclickmousedownmouseupmouseoverblur
mouseoutmousemovemouseentermouseleavecopy
key...
Does that really matter?
video not displayable
Quad core, 8 GB of RAM, Win7
Seems so...
video not displayable
SOLUTION: write custom directive(s), catch the events you need and...
.directive('customMouseEnter',[
function(){
'usestri...
...trigger local $digests (DEMO $digest over $apply)
//TEMPLATE
<trcustom-mouse-enter="ctrlMouseLeave">
//CONTROLLER/DIREC...
Seems to be pretty common in the community
http://stackoverflow.com/questions/18421732/angularjs-how-to-override-directive...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
5. Splitting the page
identify what is shareable and what is not
avoid splitting the page in too many sub-components
design your components in a...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
6. Miscenallaneous
(1) evalAsync(f) over $timeout(f)
More: http://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm
(2) Watch out for external components performance and their usage
We had a problem with Moment.JS library (20% of the page...
(3) $eval your code from time to time - PERF wise
Batarang (identify $watchers), Chrome Profiler (memory, performance), pe...
(BONUS) demythify events
$emit / $broadcast (1)
SOURCE: jsperf.com/rootscope-emit-vs-rootscope-broadcast/24
$emit / $broadcast (2)
SOURCE: jsperf.com/rootscope-emit-vs-rootscope-broadcast/25
Ok... but why?
AngularJS 1.2.6 and below ▶ 12-15x difference
AngularJS 1.2.7+ ▶ 1.1x difference
"limit propagation of $bro...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
7. Limits
"you quickly reach the end of what Angular can do for you when it comes to structuring
applications, at which point the co...
Technical limits
1. + 2.000 dynamic elements on the screen
2. + 3.000 watchers
3. real time apps, where data changes very ...
Some apps examples:
stocks exchange
google maps
office apps
OUTPUT: screen flickering, low UX, unresponsive screens
And th...
1. View watches / data bindings
2. What you see is what you show
3. The risk of polluting scopes
4. Core directives to avo...
Recap? (1)
(1) be aware of too many data bindings (bindonce)
(2) try to minimize the number of $digest cycles
(3) have pre...
Recap? (2)
(5) be aware of core directives PERF problems
(6) don't pollute your scopes and make them TDD friendly
(7) watc...
What's next?
it's a good habit to think PERF (pre-$compile the code in your head)
don't assume the frameworks are fast, wh...
Q / A
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Dragos Rusu  - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014
Upcoming SlideShare
Loading in …5
×

Dragos Rusu - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014

422 views

Published on

Dragos Rusu - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014

Published in: Software
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
422
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Dragos Rusu - Angular JS - Overcoming Performance Issues - CodeCamp-10-may-2014

  1. 1. AngularJS. Performance & Limits. Dragos Rusu - CodeCamp Iasi 2014 (dragos.rusu@bytex.ro)
  2. 2. Our story From "We have to rethink this whole module, remove time navigation... it's just too sluggish." ★ to "It's awesome, really fast, it's like going from night to day!" ★ (★) SOFTVISION customer
  3. 3. A few words about me Dragos Rusu @ SOFTVISION WEB/ZEND ENGINEER since 2007 (backend, frontend) ARTICLE WRITER (PHP Architect) PROJECTS: platforms for airlines (Cathay Pacific, Singapore Airlines, Air Berlin), tourism agencies, home automation and security, agriculture
  4. 4. We will discuss about... 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits Q / A
  5. 5. disclaimer PERFORMANCE principles for heavy apps (+500 man days) * many items are not covered here. * code samples - only in AngularJS never used AngularJS before? no problem, principles are general, yet the solutions are particular.
  6. 6. Shall we?
  7. 7. 1. View watches / data bindings
  8. 8. GENERAL CONTEXT "more of 2000 watchers can lag the UI" (angular-tips.com) "the expressions in curly braces denote bindings" ({{ ... }}) (docs.angularjs.org) "AngularJS internally creates a $watch for each ng-* directive" (github.com/Pasvaz/bindonce) "ngRepeat directive instantiates a template once per item [...] each template instance gets its own scope" (docs.angularjs.org)
  9. 9. Ok... but why would I be counting watches?
  10. 10. Every watcher is run at the digest cycle. The digest cycle is repeated until none of the results has changed value (Brian Ford - AngularJS contributor)
  11. 11. ✈ A peak into AngularJS source code $apply:function(expr){ try{ beginPhase('$apply'); returnthis.$eval(expr); }catch(e){$exceptionHandler(e); }finally{ clearPhase(); try{ $rootScope.$digest();//Ouhmy... //[...] ? https://github.com/angular/angular.js/blob/ master/src/ng/rootScope.js#L943
  12. 12. (1) double-binding creates tons of listeners
  13. 13. SOLUTION: Whenever feasible, use single-binding solutions double binding DEMO / bindonce DEMO
  14. 14. Why? Is double-binding slow? Not quite. The AngularJS way of implementing it is slow ($dirty flags instead of observable properties). pssst: ECMA6: Object.observe()
  15. 15. github.com/Pasvaz/bindonce github.com/kseamon/fast-bind pssst: bindonce will be part of AngularJS 1.3 release!
  16. 16. (2) direct function calls from templates are called very often SOLUTION: pre-compute the values to shown in the view model (default values, totals, etc) <ul> <ling-repeat="iteminitems"> //{{item.name}}({{computeTotal(item)}}) {{item.name}}({{item.computedTotal}}) </li> </ul> ?
  17. 17. EXAMPLE vatTotal will be recomputed on each scope $digest, regardless if the values that vatTotal() depend on are changed or not (DEMO) //...controller... $scope.vat=24;//% $scope.vatTotal=function(){ return( $scope.data.item.total* (1+$scope.vat/100) ); }; //...template... {{vatTotal()}} ?
  18. 18. (3) iterating over large data sets slows down the page SOLUTION: create a lightweight iterable view model angular.module('codecamp').controller('testCtrl',[ '$scope','dm','$q',function($scope,dm,$q){ 'usestrict'; $scope._init=function(){ $scope.testViewModel={}; $q.all([dm.getData1(),dm.getData2()]) .then(function(response){ $scope.computeViewModel(response.data); } ); }; $scope._init(); } ); ?
  19. 19. (4) ng-repeat extra DOM manipulations SOLUTION: ng-repeat with track by id (DEMO) <ul> <ling-repeat="iteminitemstrackbyitem.id"> {{item.name}} </li> </ul> ?
  20. 20. (5) filters are called very often SOLUTION: lightweight quasi-independent filters <span>{{value}}</span> <ul> <ling-repeat="iteminitems"> {{item.name|heavyFilteritem.value,$index}} </li> </ul> ? WARNING: avoid touching DOM in filters and watches
  21. 21. (6) multiple recursive $watch might cause page flickering SOLUTION: try to avoid recursive watch, where feasible $scope.$watch('model.items', function(newValue,oldValue){ //dosmth },recursive=true); ); ?
  22. 22. (7) direct DOM watch functions might slow down the page SOLUTION: try to avoid complex valueExpression, where feasible (use the data model instead) //DirectiveLINKfunction link:function($scope,$el,$attrs){ $scope.$watch( function(){return$el[0].childNodes.length;}, function(newValue,oldValue){} ); } ? SOURCE: stackoverflow.com/questions/21332671
  23. 23. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  24. 24. 2. What you see is what you show
  25. 25. ng-if vs. ng-show (1) ng-hide and ng-show makes no speed difference (DEMO) <ulng-hide="hideCondition"> <ling-repeat="iteminitems"> {{item.value}} </li> </ul> ?
  26. 26. ng-if vs. ng-show (2) ng-if/ng-switch might make a difference on more content (e.g. tabbed page) <ulng-if="displayCondition"> //CONTENT </ul> ? * fewer bindings * fewer linkers called at startup
  27. 27. remove non-visible elements in the scroll (1) one easy way would be PAGINATION doesn't always apply though...
  28. 28. remove non-visible elements in the scroll (2) DISPLAY elements, but ONLY THE VISIBLE ones known as the VIRTUAL/INFINITE SCROLLING problem
  29. 29. remove non-visible elements in the scroll (3) usually occurs when large data sets need to be displayed OpenSource solutions: http://binarymuse.github.io/ngInfiniteScroll/ http://blog.stackfull.com/2013/02/AngularJS-virtual-scrolling-part-1/ DEMO / DEMO (with virtual scroll)
  30. 30. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  31. 31. 3. The risk of polluting scopes
  32. 32. ✈ DOM / SCOPES
  33. 33. (1) relying on multiple $rootScope and appCtrl functions may slow down the $digest SOLUTION: try to avoid polluting $rootScope/appCtrl/* scopes angular.module('codecamp').service('appInit',[ '$rootScope',function($rootScope){ 'usestrict'; $rootScope.computeStuff=function(){...}; $rootScope.getData=function(){...}; $rootScope.i18n=function(){...}; $rootScope.manageAppStates=function(){...}; $rootScope.manageFormatters=function(){...}; //...andsoforth }); ? - dispatch to specialized services/factories/filters/*
  34. 34. ... and have some privacy in all scopes angular.module('codecamp').controller('testCtrl',[ '$scope',function($scope){ 'usestrict'; $scope._privateMethod=function(){}; functionnotRecommended(){ //... } }); ?
  35. 35. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  36. 36. 4. Core directives to avoid
  37. 37. ALL of them ... right
  38. 38. Remember what we've said earlier? "more of 2000 watchers can lag the UI" (angular-tips.com)
  39. 39. varngEventDirectives={};forEach( 'clickdblclickmousedownmouseupmouseoverblur mouseoutmousemovemouseentermouseleavecopy keydownkeyupkeypresssubmitfocuscutpaste' .split(''),function(name){//[...] returnfunction(scope,element,attr){//LINK element.on(lowercase(name),function(event){ //scope.$apply=>$rootScope.$apply scope.$apply(function(){ fn(scope,{$event:event}); }); //[...] ? SOURCE: github.com/angular/angular.js/blob/ master/src/ng/directive/ngEventDirs.js#L41
  40. 40. Does that really matter? video not displayable Quad core, 8 GB of RAM, Win7
  41. 41. Seems so... video not displayable
  42. 42. SOLUTION: write custom directive(s), catch the events you need and... .directive('customMouseEnter',[ function(){ 'usestrict'; return{ restrict:'A', link:function(scope,elem,attrs){ varfName=attrs.customMouseEnter, func=function(ev){ scope[fName](ev); }; elem.on('mouseenter',func); scope.$on('$destroy',function(){ elem.off('mouseenter',func); }); //[...] ?
  43. 43. ...trigger local $digests (DEMO $digest over $apply) //TEMPLATE <trcustom-mouse-enter="ctrlMouseLeave"> //CONTROLLER/DIRECTIVE scope.mouseLeave=function(ev){ //highlight,etc //$digest()onlyonthescopeyouneed scope.$digest(); }; ?
  44. 44. Seems to be pretty common in the community http://stackoverflow.com/questions/18421732/angularjs-how-to-override-directive-ngclick http://briantford.com/blog/angular-hacking-core (★) if you actually override default directives, remember to set a higher priority
  45. 45. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  46. 46. 5. Splitting the page
  47. 47. identify what is shareable and what is not avoid splitting the page in too many sub-components design your components in a blackbox manner
  48. 48. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  49. 49. 6. Miscenallaneous
  50. 50. (1) evalAsync(f) over $timeout(f) More: http://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm
  51. 51. (2) Watch out for external components performance and their usage We had a problem with Moment.JS library (20% of the page load time, according to Chrome Profiler)
  52. 52. (3) $eval your code from time to time - PERF wise Batarang (identify $watchers), Chrome Profiler (memory, performance), performance.now()
  53. 53. (BONUS) demythify events
  54. 54. $emit / $broadcast (1) SOURCE: jsperf.com/rootscope-emit-vs-rootscope-broadcast/24
  55. 55. $emit / $broadcast (2) SOURCE: jsperf.com/rootscope-emit-vs-rootscope-broadcast/25
  56. 56. Ok... but why? AngularJS 1.2.6 and below ▶ 12-15x difference AngularJS 1.2.7+ ▶ 1.1x difference "limit propagation of $broadcast to scopes that have listeners for the event" (github.com/angular/angular.js/blob/master/CHANGELOG.md#performance-improvements-3) RECAP: Common sense still says we should use them according to their design
  57. 57. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  58. 58. 7. Limits
  59. 59. "you quickly reach the end of what Angular can do for you when it comes to structuring applications, at which point the community fragments transform to best practices, and few people have figured out how to write large-scale Angular apps" (EmberJS core member)
  60. 60. Technical limits 1. + 2.000 dynamic elements on the screen 2. + 3.000 watchers 3. real time apps, where data changes very often (★) depending on the device
  61. 61. Some apps examples: stocks exchange google maps office apps OUTPUT: screen flickering, low UX, unresponsive screens And there's nothing you can do about it... except rewriting it in a lightweight framework
  62. 62. 1. View watches / data bindings 2. What you see is what you show 3. The risk of polluting scopes 4. Core directives to avoid 5. Splitting the page 6. Miscellaneous 7. Limits
  63. 63. Recap? (1) (1) be aware of too many data bindings (bindonce) (2) try to minimize the number of $digest cycles (3) have pre-computed values at template level (4) display only the visible elements (virtual scroll)
  64. 64. Recap? (2) (5) be aware of core directives PERF problems (6) don't pollute your scopes and make them TDD friendly (7) watch out for external components (angular or non-angular) performance
  65. 65. What's next? it's a good habit to think PERF (pre-$compile the code in your head) don't assume the frameworks are fast, whatever you may write watch out for memory leaks REMINDER: AngularJS is quite easy, just try it! ... and last but not least important: find a company that would allow you to grow your skills!
  66. 66. Q / A

×