16
Full Stack Toronto AngularJS $scope and $digest Loop Deep Dive

AngularJS: $scope and $digest Loop Deep Dive

Embed Size (px)

Citation preview

Page 1: AngularJS: $scope and $digest Loop Deep Dive

Full Stack Toronto

AngularJS

$scope and $digest Loop

Deep Dive

Page 2: AngularJS: $scope and $digest Loop Deep Dive

Topics to Cover

l$scope relationships

l$digest & $apply

l$watches & $observes

Page 3: AngularJS: $scope and $digest Loop Deep Dive

$scope – two parent-child relationships

lPrototype inheritance

lChild scopes can isolated or prototypally inherit from its parent

scope in the hierarchy

lHierarchy

l$parent property to reference the parent

lChild Nodes are organized in a linked list instead of an array for

performance reason because they are frequently created and

destroyed and array modification routines are more expensive than

updating references in a linked list

l$childHead – first child

l$childTail – last child

Page 4: AngularJS: $scope and $digest Loop Deep Dive

$scope – two parent-child relationships

lHierarchy (continued)

lSiblings

l$nextSibling

l$prevSibling

lCode Demo

lPrototype Inheritance

l$scope Hierarchy

Page 5: AngularJS: $scope and $digest Loop Deep Dive

Why prototype inheritance?

lAll of functionality needed for a $scope is attached to the

$rootScope, and made available via prototype inheritance to all

non-isolated child $scopeslNote: isolation refers to prototype inheritance, not the linked heirarchy

of $scopes

lPrototype inheritance is preferred over a closure because it is

more efficient and uses less memory

Page 6: AngularJS: $scope and $digest Loop Deep Dive

Isolated $scope

lNormally, scopes will prototypally inherit from their parent in the

hierarchy

lHowever, isolated scopes can be created that have a $parent

reference, but they do not inherit prototypally from their parent or

any other scopelSome people think an isolated $scope inherits from the $rootScope,

this is not true

lCode demo to examine child scope which are and are not

isolated

Page 7: AngularJS: $scope and $digest Loop Deep Dive

When to isolate and when not to isolate...

lIn AngularJS,lScopes created by ng-controller always prototypally inherit

lScopes created using $new will prototypally inherit unless true is

passed inlPrimarily, used when assigning a $scope to transcluded content

lScopes created by directives can prototypally inherit or be

isolatedlAlways prefer an isolated scope for maximum directive reusability

Page 8: AngularJS: $scope and $digest Loop Deep Dive

$digest Loop

lChild $scope traversallDepth first, starting from the $scope object from which it is called

lDoes not traverse up from the $scope object from which it is called

lPrototypal inheritance (isolated scopes) does not impact the $digest

loop traversal processlIt follows the linked hierarchy of the scopes not the prototypal inheritance

hierarchy

lCode Demo

Page 9: AngularJS: $scope and $digest Loop Deep Dive

$digest Loop TTL

lWhenever a value on the $scope is changed during the $digest

loop, it causes the $digest loop to execute againlThe $digest loop will trigger itself up to 10 (by default) times before it

stops and throws an error to prevent an infinite loop

lIf you need to increase this value, you can do so in a config function,

by passing in the $rootScopeProvider and calling digestTtl function

and passing in the new TTL valuelNote – only increase this value if you really know what you are doing as it can

adversely impact the performance and user experience of your AngularJS

application

lCode Demo

Page 10: AngularJS: $scope and $digest Loop Deep Dive

$apply

lProvides a try/catch/finally structure to properly handle errorslReview AngularJS Source Code

lDemo Try/Catch/Finally

lPasses the function argument to the $eval function on the

$scope from which $apply is calledlCan be called without passing a function to simply safely call the

$digest function

lAfter executing $eval, $digest on the $rootScope is called

Page 11: AngularJS: $scope and $digest Loop Deep Dive

$$postDigest & $timeout

lTo execute code one time after a completed $digest cycle there

are two methodsl$$postDigest

lNot recommended, the double $ means its a private function to AngularJS

lSimply pass a function to the method and it will be executed after the $digest

loop and it will not trigger another $digest loop

lStores functions in a queue that are executed at the end of the $digest Loop

after the $digest phase has been cleared

lAdvantage – no delay between $$postDigest functions and completion of

$digest phase

Page 12: AngularJS: $scope and $digest Loop Deep Dive

$$postDigest & $timeout

l$timeoutl0 for delay and false for invokeApply

lPublic method, returns a promise

lMust be called during the $apply or $digest to queue up to execute after the

$digest loop has completed

lLimitation – because of the single threaded nature of JavaScript, it will be

queued up after the last task in the JavaScript event loop which could mean it

could possibly not be executed immediately after the $digest loop completes

Page 13: AngularJS: $scope and $digest Loop Deep Dive

$digest & $apply Summary

lSimilaritylBoth trigger the $digest loop

lDifferencesl$digest starts from the $scope on which it is called

l$apply executes the $digest from the $rootScope

lAdditionallyl$apply executes the expression on the $scope from which it is called

using $eval

l$apply provides error handling, calling $digest on the $rootScope from

a finally block

Page 14: AngularJS: $scope and $digest Loop Deep Dive

$watches and $observes

lBoth are executed during the $digest loop

l$watches can be configured in controllers, $observes cannot be

lBoth $watches and $observes can be configured in directives,

usually, within the post-link function

l$watches can only observe a property on the scope, $observes

only observe an attribute of an element on which a directive is

applied but it can observe an interpolated expression

Page 15: AngularJS: $scope and $digest Loop Deep Dive

$watches and $observes

l$watches require move overhead then $observes, as such,

$observes are preferred over $watches

l$watches require the execution of a conditional function that

checks to see if the value has changed, then it executes the

listener functionlThe conditional function must execute for each watcher; therefore, do

not place multiple watchers on the same conditional function, place on

watcher and have it handle multiple things

l$observes simply observe an interpolated attribute value, if it

changes then all of the $observe functions exectutelThis requires less overhead than a $watch

Page 16: AngularJS: $scope and $digest Loop Deep Dive

Best Practices

- Always, prefer an isolated $scope for directive to ensure loose

coupling with the surrounding $scope and directive reusability

- Use $apply instead of $digest directly unless you have a large

scope model and need to limit the number of child scopes the

$digest function is executed against

- Limit the use of $watches and $observes to UI affecting events

and when possible choose an $observe over a $watch

- Never $watch the same $scope property or function more than

once