AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

AngularJS the performance parts(AngularJS性能:过去现在和未来) by toddmotto

发布者 angular
发布于 1444267266828  浏览 7835 关键词 AngularJS, 前端, 框架, English 
分享到

第2页

AngularJS

the performance parts

@toddmotto



第3页

» Lead Engineer @ Mozio » Google Developer Expert » @toddmotto » Blog at toddmotto.com



第4页

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



第5页

1.2 to 1.3+



第6页

1.2 to 1.3+ generic changes



第7页

» IE8 support dropped » DOM manipulation

» ~4.3 times faster » 73% less garbage » $digest loop » ~3.5 times faster » 78% less garbage » 400+ bug fixes



第8页

1.2 to 1.3+ perf features



第9页

» One-time bind syntax » ngModelOptions » bindToController property » ngModel.$validators » ngMessage/ngMessages » strictDI » $applyAsync in $http » Disable debug info



第10页

one time bindings

<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>



第11页

one time bindings

» 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



第12页

ng-Model-Options

<!-- updateOn --> <input

type="text" ng-model="vm.model" ng-model-options="{

updateOn: 'default blur' }">



第13页

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 } }">



第14页

ng-Model-Options

// directive controller function FooDirCtrl() {

// undo model changes if (condition) {

this.model.$rollbackViewValue(); } }



第15页

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



第16页

bindToController

// directive controller function FooDirCtrl() {

this.bar = {}; this.doSomething = function doSomething(arg) {

this.bar.foobar = arg; }.bind(this); }



第17页

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); }



第18页

bindToController

function fooDirective() { return { ... scope: {}, bindToController: { name: '=' }, ... };

}



第19页

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); }



第20页

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



第21页

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);



第22页

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);



第23页

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>



第24页

ngModel.$validators

» ngModel.$validators Object » Instead of $parsers/$formatters » Return a Boolean from the bound function » Use with the $error Object in the View



第25页

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>



第26页

ngMessage/ngMessages

» Conditional validation » ngModel.$error Object » Acts like a switch case



第27页

strictDI

<div ng-app="myApp" ng-strict-di> <!-- app -->

</div>



第28页

strictDI

// implicit annotation function SomeService($scope, $timeout) {

//... }

angular .module('app') .factory('SomeService', SomeService);



第29页

strictDI

function SomeService($scope, $timeout) { //...

}

// Array annotations SomeService.$inject = ['$scope', '$timeout'];

angular .module('app') .factory('SomeService', SomeService);



第30页

strictDI

» Runs the application's $injector in strict mode

» Throws an error on Services using implicit annotations

» Use ng-annotate to automate this process



第31页

$applyAsync with $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



第32页

$applyAsync with $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



第33页

Disable debug info

function config($compileProvider) { $compileProvider.debugInfoEnabled(false);

} angular

.module('app', []) .config(config);



第34页

Disable debug info

<!-- 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>



第35页

Disable debug info

» 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();



第36页

Performance driven Angular



第37页

Understand what impacts

performance

before you code



第38页

Under the hood: $digest



第39页

$digest fundamentals

» $digest loop » $$watchers ($watch) » $$asyncQueue ($evalAsync)



第48页

$digest: $digest loop

» 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)



第49页

$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



第50页

$digest: $$asyncQueue

» $evalAsync » Runs first in $digest » May run $digest again to flush $$asyncQueue



第51页

track by

Scenarios: * Large DOM lists * Slow DOM updates * $digests blocking UI thread (lagging)



第52页

track by

<!-- before --> <ul>

<li ng-repeat="user in vm.users"> {{ user.name }}

</li> </ul>



第53页

track by

<!-- after --> <ul>

<li ng-repeat="user in vm.users track by user.id"> {{ user.name }}

</li> </ul>



第54页

track by

» Minimal DOM repaints (only what's changed) » Uses Object references instead of Angular hashes



第55页

ng-if / switch vs ng-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>



第56页

ng-if / switch vs ng-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)



第57页

ng-bind over {{ 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>



第58页

ng-bind over {{ handlebars }}

» No DOM flicker (invisible bindings) with ng-bind » Significantly faster

» ng-perf.com/2014/10/30/tip-4-ng-bind-is-fasterthan-expression-bind-and-one-time-bind

» Lesser need for ng-cloak » Angular won't evaluate entire text content



第59页

$apply or $digest?

// forces a $rootScope.$digest(); $scope.$apply();

// forces a [current $scope].$digest(); $scope.$digest();



第60页

$apply or $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



第61页

$destroy unbinding

function myFunction () { // handle element clicks

}

// bind element.on('click', myFunction); // unbind $scope.$on('$destroy', function () {

element.off('click', myFunction); });



第62页

$destroy unbinding

» 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



第63页

Deep $watch vs $watchCollection

var prop = [{...},{...},{...},{...}];

$scope.$watch('prop', function (newValue, oldValue) {

}, true);

$scope.$watchCollection('prop', function (newValue, oldValue) {

});



第64页

Deep $watch vs $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



第65页

avoiding DOM filters

<!-- vm.date = 1444175093303 --> <p>{{ vm.date | date: 'dd-MM-yyyy' }}</p>



第66页

avoiding DOM filters

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);



第67页

avoiding DOM filters

<p>{{ vm.parsedDate }}</p>



第68页

avoiding DOM filters

» DOM filters run twice per $digest » Preprocess in a Controller » Bind parsed value to the View



第69页

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



第70页

Thank you

@toddmotto speakerdeck.com/toddmotto



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。