mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-04-01 05:50:26 +00:00
refactor(scope): non-recursive $digest method
This commit is contained in:
parent
530dc412c4
commit
34f174066f
2 changed files with 49 additions and 42 deletions
87
src/Scope.js
87
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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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('');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue