diff options
| author | Misko Hevery | 2011-08-12 14:32:25 -0700 |
|---|---|---|
| committer | Igor Minar | 2011-08-14 21:32:15 -0700 |
| commit | 34f174066f1aa70dba0f97942580082169348200 (patch) | |
| tree | 98dc485ab2963109689bc6fef89cf7123690b4e6 | |
| parent | 530dc412c4d4700268e52920e6114f7941171706 (diff) | |
| download | angular.js-34f174066f1aa70dba0f97942580082169348200.tar.bz2 | |
refactor(scope): non-recursive $digest method
| -rw-r--r-- | src/Scope.js | 87 | ||||
| -rw-r--r-- | test/ScopeSpec.js | 4 |
2 files changed, 49 insertions, 42 deletions
diff --git a/src/Scope.js b/src/Scope.js index 244bd7c4..b50d6273 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -317,60 +317,67 @@ Scope.prototype = { expect(scope.counter).toEqual(1); </pre> * - * @returns {number} number of {@link angular.scope.$watch listeners} which fired. - * */ $digest: function() { - var child, - watch, value, last, - watchers = this.$$watchers, - asyncQueue = this.$$asyncQueue, - length, count = 0, - dirtyCount, ttl = 100, - recheck = !this.$parent || !this.$parent.$$phase; + var watch, value, last, next, + watchers, + asyncQueue, + length, + dirty, ttl = 100, + scope; if (this.$$phase) { throw Error(this.$$phase + ' already in progress'); } - this.$$phase = '$digest'; do { - while(asyncQueue.length) { - try { - this.$eval(asyncQueue.shift()); - } catch (e) { - this.$service('$exceptionHandler')(e); - } - } - dirtyCount = 0; - if (watchers) { - // process our watches - length = watchers.length; - while (length--) { + + dirty = false; + scope = this; + do { + scope.$$phase = '$digest'; + asyncQueue = scope.$$asyncQueue; + while(asyncQueue.length) { try { - watch = watchers[length]; - // Most common watches are on primitives, in which case we can short - // circuit it with === operator, only when === fails do we use .equals - if ((value = watch.get(this)) !== (last = watch.last) && !equals(value, last)) { - dirtyCount++; - watch.fn(this, watch.last = copy(value), last); - } + scope.$eval(asyncQueue.shift()); } catch (e) { - this.$service('$exceptionHandler')(e); + scope.$service('$exceptionHandler')(e); } } - } - child = this.$$childHead; - while(child) { - dirtyCount += child.$digest(); - child = child.$$nextSibling; - } - count += dirtyCount; + if (watchers = scope.$$watchers) { + // process our watches + length = watchers.length; + while (length--) { + try { + watch = watchers[length]; + // Most common watches are on primitives, in which case we can short + // circuit it with === operator, only when === fails do we use .equals + if ((value = watch.get(scope)) !== (last = watch.last) && !equals(value, last)) { + dirty = true; + watch.fn(scope, watch.last = copy(value), last); + } + } catch (e) { + scope.$service('$exceptionHandler')(e); + } + } + } + + + scope.$$phase = null; + // find the next scope in traversal. + if (!(next = scope.$$childHead || scope.$$nextSibling) && scope !== this) { + do { + scope = scope.$parent; + if (scope == this || (next = scope.$$nextSibling)) { + break; + } + } while (scope !== this); + } + } while (scope = next); + if(!(ttl--)) { throw Error('100 $digest() iterations reached. Aborting!'); } - } while (recheck && dirtyCount); - this.$$phase = null; - return count; + } while (dirty); }, /** diff --git a/test/ScopeSpec.js b/test/ScopeSpec.js index b3edad6c..efc8c98c 100644 --- a/test/ScopeSpec.js +++ b/test/ScopeSpec.js @@ -176,7 +176,7 @@ describe('Scope', function(){ root.$digest(); log = ''; root.a = 1; - expect(root.$digest()).toEqual(3); + root.$digest(); expect(root.b).toEqual(1); expect(root.c).toEqual(1); expect(root.d).toEqual(1); @@ -211,7 +211,7 @@ describe('Scope', function(){ root.$watch('b', function(){ log += 'b'; }); root.$digest(); log = ''; - expect(root.$digest()).toEqual(0); + root.$digest(); expect(log).toEqual(''); }); |
