Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular - Scope Inheritance (Digest loop part 2)

Angular - Scope Inheritance (Digest loop part 2)

Check out part1 here:
https://speakerdeck.com/barnash/angular-digest-loop
-------------------
Based on the second chapter of "Build Your Own Angular" book:
http://teropa.info/build-your-own-angular/

And the second part of the first deck:
Making scopes inherit from one another.

barnash

May 07, 2014
Tweet

More Decks by barnash

Other Decks in Programming

Transcript

  1. How will this session help me? - Get to know

    how scope inheritance works - Practice your JavaScript skills - Understand prototype inheritance better
  2. In the previous session - The magic behind data-binding -

    An inside look into the digest loop - $digest, $watch - Basic methods of scope
  3. A short reminder - Scope constructor - $$areEqual - $watch

    - $digest and $$digestOnce - $eval and $apply goo.gl/VWvRpS
  4. function Scope() { this.$$watchers = []; this.$$lastDirtyWatch = null; }

    Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) { if (valueEq) { return _.isEqual(newValue, oldValue); } else { return newValue === oldValue || (typeof newValue === 'number' && typeof oldValue === 'number' && isNaN(newValue) && isNaN(oldValue)); } };
  5. Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) { var self = this;

    var watcher = { watchFn: watchFn, listenerFn: listenerFn || function() {}, valueEq: !!valueEq }; self.$$watchers.push(watcher); return function() { var index = self. $$watchers.indexOf(watcher); if (index >= 0) { self. $$watchers.splice(index, 1); } } };
  6. Scope.prototype.$$digestOnce = function() { var self = this; var dirty

    = false; this.$$watchers.every(function(watch) { var newValue = watch.watchFn(self); var oldValue = watch.last; if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) { watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue); watch.listenerFn(newValue, oldValue, self); dirty = true; self.$$lastDirtyWatch = watch; } else if (self.$$lastDirtyWatch === watch) { return false; } return true; }); return dirty; };
  7. Performance Watch Watch Watch Watch Watch Watch Watch Watch Watch

    Watch Watch Watch Watch Watch Watch Watch
  8. Scope.prototype.$digest = function() { var ttl = 10; var dirty;

    this.$$lastDirtyWatch = null; do { dirty = this.$$digestOnce(); if (dirty && !(ttl--)) { throw "10 digest iterations reached"; } } while (dirty); };
  9. Scope.prototype.$eval = function(expr, locals) { return expr(this, locals); }; Scope.prototype.$apply

    = function(expr) { try { return this.$eval(expr); } finally { this.$digest(); } };
  10. Scope.$new Scope.prototype.$new = function() { var ChildScope = function() {

    }; ChildScope.prototype = this; var child = new ChildScope(); return child; };
  11. The meaning... var parent = new Scope(); parent.parentValue = [1,2,3];

    var child = parent.$new(); console.log(child.parentValue); What will be printed?
  12. The meaning... var parent = new Scope(); parent.parentValue = [1,2,3];

    var child = parent.$new(); console.log(child.parentValue); parent: { parentValue: [1,2,3] } child: { __proto__: parent } [1,2,3]
  13. The meaning… (2) var parent = new Scope(); var child

    = parent.$new(); child.childValue = [1,2,3]; console.log(parent.childValue); What will be printed?
  14. The meaning… (2) var parent = new Scope(); var child

    = parent.$new(); child.childValue = [1,2,3]; console.log(parent.childValue); parent: { } child: { __proto__: parent, childValue: [1,2,3] } undefined
  15. The meaning… (3) var parent = new Scope(); var child

    = parent.$new(); parent.parentValue = [1,2,3]; child.parentValue.push(4); console.log(parent.parentValue); What will be printed?
  16. The meaning… (3) var parent = new Scope(); var child

    = parent.$new(); parent.parentValue = [1,2,3]; child.parentValue.push(4); console.log(parent.parentValue); parent: { parentValue: [1,2,3] } child: { __proto__: parent } 1,2,3,4
  17. The meaning… (4) var parent = new Scope(); var child

    = parent.$new(); parent.name = “Ned”; child.name = “Rob”; console.log(child.name); console.log(parent.name); What will be printed?
  18. The meaning… (4) var parent = new Scope(); var child

    = parent.$new(); parent.name = “Ned”; child.name = “Rob”; console.log(child.name); console.log(parent.name); parent: { name: “Ned” } child: { __proto__: parent, name: “Rob” } Rob, Ned
  19. Q - Will this code work as expected? var parent

    = new Scope(); parent.value = “abc”; parent.$watch( function(scope) { return scope.value; }, function(newVal, oldVal, scope) { scope. watchCalled = true; } ); var child = parent.$new(); child.$digest();
  20. Separate digests Scope.prototype.$new = function() { var ChildScope = function()

    { }; ChildScope.prototype = this; var child = new ChildScope(); child.$$watchers = []; return child; };
  21. Q - Will this code work as expected? var parent

    = new Scope(); var child = parent.$new(); child.val = “abc”; child.$watch( function(scope) { return scope.val; }, function(newVal, oldVal, scope) { scope. watchCalled = true; } ); parent.$digest();
  22. Recursive digest - $new Scope.prototype.$new = function() { var ChildScope

    = function() { }; ChildScope.prototype = this; var child = new ChildScope(); this.$$children.push(child); child.$$watchers = []; child.$$children = []; return child; };
  23. Recursive digest - $$everyScope Scope.prototype.$$everyScope = function(fn) { if (fn(this))

    { return this.$$children.every(function(child) { return child.$$everyScope(fn); }); } else { return false; } };
  24. Recursive digest - $$digestOnce Scope.prototype.$$digestOnce = function() { var self

    = this; var dirty = false; var continueLoop = true; ...
  25. this.$$everyScope(function(scope) { scope.$$watchers.every(function(watch) { var newValue = watch.watchFn(scope); var oldValue

    = watch.last; if (!scope.$$areEqual(newValue, oldValue, watch.valueEq)) { watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue); watch.listenerFn(newValue, oldValue, scope); dirty = true; self.$$lastDirtyWatch = watch; } else if (self.$$lastDirtyWatch === watch) { continueLoop = false; return false; } return true; }); return continueLoop; }); return dirty; };
  26. Watch Watch Watch Watch Watch Watch Watch Watch Watch Watch

    Watch Watch Watch Watch Watch Watch Child 3 Parent Child 2 Child 1
  27. $apply vs $digest - $$root function Scope() { this.$$watchers =

    []; this.$$lastDirtyWatch = null; this.$$children = []; this.$$root = this; }
  28. $apply vs $digest - $apply Scope.prototype.$apply = function(expr) { try

    { return this.$eval(expr); } finally { this.$$root.$digest(); } };
  29. Isolated scopes Scope.prototype.$new = function(isolated) { var child; if (isolated)

    { child = new Scope(); } else { var ChildScope = function() { }; ChildScope.prototype = this; child = new ChildScope(); } this.$$children.push(child); child.$$watchers = []; child.$$children = []; return child; };
  30. Isolated scopes (2) Scope.prototype.$new = function(isolated) { var child; if

    (isolated) { child = new Scope(); child.$$root = this.$$root; } else { var ChildScope = function() { }; ChildScope.prototype = this; child = new ChildScope(); } this.$$children.push(child); child.$$watchers = []; child.$$children = []; return child; };
  31. Destroying Scopes - $new Scope.prototype.$new = function(isolated) { var child;

    if (isolated) { child = new Scope(); child.$$root = this.$$root; } else { var ChildScope = function() { }; ChildScope.prototype = this; child = new ChildScope(); } this.$$children.push(child); child.$$watchers = []; child.$$children = []; child.$parent = this; return child; };
  32. Scope.prototype.$destroy = function() { if (this === this.$$root) { return;

    } var siblings = this.$parent.$$children; var indexOfThis = siblings.indexOf(this); if (indexOfThis >= 0) { siblings.splice(indexOfThis, 1); } }; Destroying Scopes - $destroy
  33. Basically... - Scope inheritance - Recursive $digest - Scope Isolation

    - Destroying scopes http://teropa.info/build-your-own-angular