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.

Angular Performance: Then, Now and the Future. Todd Motto

11,265 views

Published on

FOWA London 2015

Covering Angular of the past and present, and diving into the future - covering performance aspects and practices, how they work and why you should adopt them.

Published in: Technology, Software
  • Girls for sex in your area are there: tinyurl.com/areahotsex
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • account activity. WTF!! Why I’m being penalized for winning?? Has this happened to you? Also just checked your web page again…you’re giving this service away for £30 . HAVE YOU LOST YOUR MIND?!!! ◆◆◆ http://t.cn/A6vAxKsh
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Real people just like you are kissing the idea of punching the clock for someone else goodbye, and embracing a new way of living. The internet economy is exploding, and there are literally THOUSANDS of great earnings opportunities available right now, all just one click away. ♥♥♥ http://t.cn/AisJWUCf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Sex in your area is here: ♥♥♥ http://bit.ly/2ZDZFYj ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Dating direct: ♥♥♥ http://bit.ly/2ZDZFYj ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Angular Performance: Then, Now and the Future. Todd Motto

  1. AngularJS the performance parts@toddmotto
  2. » Lead Engineer @ Mozio » Google Developer Expert » @toddmotto » Blog at toddmotto.com
  3. Topics » New features (1.2 - 1.3+) » Generic changes » Perf features » Performance driven Angular » $digest loop/$$watchers/$$asyncQueue » Quick wins, tips and tricks » Structure practices, advanced techniques
  4. 1.2to1.3+
  5. 1.2to1.3+genericchanges
  6. » IE8 support dropped » DOM manipulation » ~4.3 times faster » 73% less garbage » $digest loop » ~3.5 times faster » 78% less garbage » 400+ bug fixes
  7. 1.2to1.3+perffeatures
  8. » One-time bind syntax » ngModelOptions » bindToController property » ngModel.$validators » ngMessage/ngMessages » strictDI » $applyAsync in $http » Disable debug info
  9. onetimebindings <p>{{ ::vm.name }}</p> <p ng-bind="::vm.name"></p> <div ng-if="::vm.user.loggedIn"></div> <div ng-class="::{ loggedIn: vm.user.loggedIn }"></div> <ul> <li ng-repeat="user in ::vm.users"> {{ ::user.name }} </li> </ul>
  10. onetimebindings » Defined with :: » $watched until not "undefined" » $$watcher is unbound » Will not update upon Model changes » One-time, not one-way » Great for single static rendering
  11. ng-Model-Options <!-- updateOn --> <input type="text" ng-model="vm.model" ng-model-options="{ updateOn: 'default blur' }">
  12. ng-Model-Options <!-- debounce: - example will debounce 250ms when typing - example will update model immediately on "blur" --> <input type="text" ng-model="vm.model" ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 250, 'blur': 0 } }">
  13. ng-Model-Options // directive controller function FooDirCtrl() { // undo model changes if (condition) { this.model.$rollbackViewValue(); } }
  14. ng-Model-Options » Fine tune how Model updates are done » Define event types » Add debounce to delay Model synchronisation » e.g. { debounce: 250 } = $digest ~250ms » $rollbackViewValue for undoing model changes
  15. bindToController // directive controller function FooDirCtrl() { this.bar = {}; this.doSomething = function doSomething(arg) { this.bar.foobar = arg; }.bind(this); }
  16. bindToController // directive controller function FooDirCtrl($scope) { this.bar = {}; this.doSomething = function doSomething(arg) { this.bar.foobar = arg; // reference the isolate property $scope.name = arg.prop; }.bind(this); }
  17. bindToController function fooDirective() { return { ... scope: {}, bindToController: { name: '=' }, ... }; }
  18. bindToController // directive controller function FooDirCtrl() { this.bar = {}; this.doSomething = function doSomething(arg) { this.bar.foobar = arg; // reference the isolate property this.name = arg.prop; }.bind(this); }
  19. bindToController » Used with "controllerAs" (class-like) » Binds isolate props to the Controller instance » No $scope » $scope remains "special use only" » Not used for data » Used for $watch/$on/etc
  20. ngModel.$validators // old school function visaValidator() { var VISA_REGEXP = /^4[0-9]{12}(?:[0-9]{3})?$/; function link($scope, element, attrs, ngModel) { ngModel.$parsers.unshift(function (value) { var valid = VISA_REGEXP.test(value); ngModel.$setValidity('visaValidator', valid); return valid ? value : undefined; }); } return { require : 'ngModel', link : link }; } angular.module('app').directive('visaValidator', visaValidator);
  21. ngModel.$validators // new school function visaValidator() { var VISA_REGEXP = /^4[0-9]{12}(?:[0-9]{3})?$/; function link($scope, element, attrs, ngModel) { ngModel.$validators.visaValidator = function (value) { return VISA_REGEXP.test(value); // Boolean }; } return { require : 'ngModel', link : link }; } angular.module('app').directive('visaValidator', visaValidator);
  22. ngModel.$validators <form name="myForm"> <label> <input type="text" ng-model="myForm.card" visa-validator> <div ng-if="myForm.myPassword.$error.visaValidator"> Not a valid VISA format! </div> </label> </form>
  23. ngModel.$validators » ngModel.$validators Object » Instead of $parsers/$formatters » Return a Boolean from the bound function » Use with the $error Object in the View
  24. ngMessage/ngMessages <form name="myForm"> <label> Enter email: <input type="text" ng-model="field" name="myField" required ng-minlength="5" ng-maxlength="100"> </label> <div ng-messages="myForm.myField.$error" role="alert"> <div ng-message="required"> You did not enter a field </div> <div ng-message="minlength, maxlength"> Your email must be between 5 and 100 characters long </div> </div> </form>
  25. ngMessage/ngMessages » Conditional validation » ngModel.$error Object » Acts like a switch case
  26. strictDI <div ng-app="myApp" ng-strict-di> <!-- app --> </div>
  27. strictDI // implicit annotation function SomeService($scope, $timeout) { //... } angular .module('app') .factory('SomeService', SomeService);
  28. strictDI function SomeService($scope, $timeout) { //... } // Array annotations SomeService.$inject = ['$scope', '$timeout']; angular .module('app') .factory('SomeService', SomeService);
  29. strictDI » Runs the application's $injector in strict mode » Throws an error on Services using implicit annotations » Use ng-annotate to automate this process
  30. $applyAsyncwith$http function config($httpProvider) { $httpProvider.useApplyAsync(true); } angular .module('app', []) .config(config); More: blog.thoughtram.io/angularjs/2015/01/14/exploring-angular-1.3-speed-up-with-applyAsync.html
  31. $applyAsyncwith$http » Enables $applyAsync to be used with $http » Schedules an async $apply for batched requests » For requests that resolve within ~10ms » Pushes into $$asyncQueue » Single $digest
  32. Disabledebuginfo function config($compileProvider) { $compileProvider.debugInfoEnabled(false); } angular .module('app', []) .config(config);
  33. Disabledebuginfo <!-- enabled --> <div ng-controller="MainCtrl as vm" class="ng-scope ng-binding"> <my-directive class="ng-isolate-scope"> // content </my-directive> </div> <!-- disabled --> <div ng-controller="MainCtrl as vm"> <my-directive> // content </my-directive> </div>
  34. Disabledebuginfo » Disable in production for performance boosts » Removes $scope references on elements » Doesn't add classes to DOM nodes with binding info » Enable in console with angular.reloadWithDebugInfo();
  35. PerformancedrivenAngular
  36. Understandwhatimpacts performance beforeyou code
  37. Underthe hood: $digest
  38. $digestfundamentals » $digest loop » $$watchers ($watch) » $$asyncQueue ($evalAsync)
  39. $digest: $digestloop » Triggered by $scope.$apply / built-in events » Iterates $$watchers Array on $scope » If model value is different from last calculated then corresponding listener executes » Exits loop, Angular loops again (10 max) » Repaints DOM (View expressions updated)
  40. $digest: $$watchers » View events/bindings {{ foo }} » Angular adds a watch to the $watch list » Only $watched if bound in the View » Dirty checked in the $digest loop » Minimise use of $$watchers / avoid if possible
  41. $digest: $$asyncQueue » $evalAsync » Runs first in $digest » May run $digest again to flush $$asyncQueue
  42. trackby Scenarios: * Large DOM lists * Slow DOM updates * $digests blocking UI thread (lagging)
  43. trackby <!-- before --> <ul> <li ng-repeat="user in vm.users"> {{ user.name }} </li> </ul>
  44. trackby <!-- after --> <ul> <li ng-repeat="user in vm.users track by user.id"> {{ user.name }} </li> </ul>
  45. trackby » Minimal DOM repaints (only what's changed) » Uses Object references instead of Angular hashes
  46. ng-if/switchvsng-show/hide <!-- ng-show --> <ul ng-show="vm.exposeNav"> <li ng-repeat="menu in vm.menus"></li> </ul> <!-- ng-if --> <ul ng-if="vm.exposeNav"> <li ng-repeat="menu in vm.menus"></li> </ul>
  47. ng-if/switchvsng-show/hide » ng-if/switch reconstruct the DOM » ng-if/switch for less frequent/heavier rendering » ng-show/hide toggle "ng-hide" class » ng-show/hide for more frequent/lighter rendering » ng-show/hide less performant due to $$watchers (when hidden)
  48. ng-bindover{{handlebars}} <!-- handlebars --> <p>{{ vm.username }}</p> <!-- ng-bind --> <p ng-bind="vm.username"></p> <!-- perf example --> <p> Welcome <span ng-bind="vm.username"></span> to Facebook </p>
  49. ng-bindover{{handlebars}} » No DOM flicker (invisible bindings) with ng-bind » Significantly faster » ng-perf.com/2014/10/30/tip-4-ng-bind-is-faster- than-expression-bind-and-one-time-bind » Lesser need for ng-cloak » Angular won't evaluate entire text content
  50. $applyor$digest? // forces a $rootScope.$digest(); $scope.$apply(); // forces a [current $scope].$digest(); $scope.$digest();
  51. $applyor$digest? » $scope certainties » Prevent a full $rootScope.$digest() if you're certain only child $scopes need updating » Improve performance by not forcing a full $rootScope.$digest » $scope.$digest runs on current and child $scopes » $scope.$apply triggers $rootScope.$digest call
  52. $destroyunbinding function myFunction () { // handle element clicks } // bind element.on('click', myFunction); // unbind $scope.$on('$destroy', function () { element.off('click', myFunction); });
  53. $destroyunbinding » Remove event listeners that may cause memory leaks » DOM nodes that are destroyed » Manually unbind by listening to $destroy » $scope.$on events are automatically removed
  54. Deep$watchvs$watchCollection var prop = [{...},{...},{...},{...}]; $scope.$watch('prop', function (newValue, oldValue) { }, true); $scope.$watchCollection('prop', function (newValue, oldValue) { });
  55. Deep$watchvs$watchCollection » Deep $watch uses deep Object tree comparison (expensive) » $watchCollection goes only one level deep » Shallow reference of all top level items » Try not to use either unless you have to » Not as testable » Signs of bad architecture » Litter Controllers
  56. avoidingDOMfilters <!-- vm.date = 1444175093303 --> <p>{{ vm.date | date: 'dd-MM-yyyy' }}</p>
  57. avoidingDOMfilters function SomeCtrl($filter) { // date passed in elsewhere var time = 1444175093303; // Parsed in JS before bound to the DOM this.parsedDate = $filter('date')(time, 'dd-MM-yyyy'); } angular .module('app') .controller('SomeCtrl', SomeCtrl);
  58. avoidingDOMfilters <p>{{ vm.parsedDate }}</p>
  59. avoidingDOMfilters » DOM filters run twice per $digest » Preprocess in a Controller » Bind parsed value to the View
  60. Takeaways » Understand the $digest loop » Investigate the performance side of each Directive/API you use » Consider using JavaScript over DOM bindings where possible ($filter etc.) » Check Angular's GitHub repo for changelogs/ releases
  61. Thankyou @toddmotto speakerdeck.com/toddmotto

×