Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 34f1740

Browse files
mheveryIgorMinar
authored andcommitted
refactor(scope): non-recursive $digest method
1 parent 530dc41 commit 34f1740

File tree

2 files changed

+49
-42
lines changed

2 files changed

+49
-42
lines changed

src/Scope.js

+47-40
Original file line numberDiff line numberDiff line change
@@ -317,60 +317,67 @@ Scope.prototype = {
317317
expect(scope.counter).toEqual(1);
318318
</pre>
319319
*
320-
* @returns {number} number of {@link angular.scope.$watch listeners} which fired.
321-
*
322320
*/
323321
$digest: function() {
324-
var child,
325-
watch, value, last,
326-
watchers = this.$$watchers,
327-
asyncQueue = this.$$asyncQueue,
328-
length, count = 0,
329-
dirtyCount, ttl = 100,
330-
recheck = !this.$parent || !this.$parent.$$phase;
322+
var watch, value, last, next,
323+
watchers,
324+
asyncQueue,
325+
length,
326+
dirty, ttl = 100,
327+
scope;
331328

332329
if (this.$$phase) {
333330
throw Error(this.$$phase + ' already in progress');
334331
}
335-
this.$$phase = '$digest';
336332
do {
337-
while(asyncQueue.length) {
338-
try {
339-
this.$eval(asyncQueue.shift());
340-
} catch (e) {
341-
this.$service('$exceptionHandler')(e);
342-
}
343-
}
344-
dirtyCount = 0;
345-
if (watchers) {
346-
// process our watches
347-
length = watchers.length;
348-
while (length--) {
333+
334+
dirty = false;
335+
scope = this;
336+
do {
337+
scope.$$phase = '$digest';
338+
asyncQueue = scope.$$asyncQueue;
339+
while(asyncQueue.length) {
349340
try {
350-
watch = watchers[length];
351-
// Most common watches are on primitives, in which case we can short
352-
// circuit it with === operator, only when === fails do we use .equals
353-
if ((value = watch.get(this)) !== (last = watch.last) && !equals(value, last)) {
354-
dirtyCount++;
355-
watch.fn(this, watch.last = copy(value), last);
356-
}
341+
scope.$eval(asyncQueue.shift());
357342
} catch (e) {
358-
this.$service('$exceptionHandler')(e);
343+
scope.$service('$exceptionHandler')(e);
359344
}
360345
}
361-
}
362-
child = this.$$childHead;
363-
while(child) {
364-
dirtyCount += child.$digest();
365-
child = child.$$nextSibling;
366-
}
367-
count += dirtyCount;
346+
if (watchers = scope.$$watchers) {
347+
// process our watches
348+
length = watchers.length;
349+
while (length--) {
350+
try {
351+
watch = watchers[length];
352+
// Most common watches are on primitives, in which case we can short
353+
// circuit it with === operator, only when === fails do we use .equals
354+
if ((value = watch.get(scope)) !== (last = watch.last) && !equals(value, last)) {
355+
dirty = true;
356+
watch.fn(scope, watch.last = copy(value), last);
357+
}
358+
} catch (e) {
359+
scope.$service('$exceptionHandler')(e);
360+
}
361+
}
362+
}
363+
364+
365+
scope.$$phase = null;
366+
// find the next scope in traversal.
367+
if (!(next = scope.$$childHead || scope.$$nextSibling) && scope !== this) {
368+
do {
369+
scope = scope.$parent;
370+
if (scope == this || (next = scope.$$nextSibling)) {
371+
break;
372+
}
373+
} while (scope !== this);
374+
}
375+
} while (scope = next);
376+
368377
if(!(ttl--)) {
369378
throw Error('100 $digest() iterations reached. Aborting!');
370379
}
371-
} while (recheck && dirtyCount);
372-
this.$$phase = null;
373-
return count;
380+
} while (dirty);
374381
},
375382

376383
/**

test/ScopeSpec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe('Scope', function(){
176176
root.$digest();
177177
log = '';
178178
root.a = 1;
179-
expect(root.$digest()).toEqual(3);
179+
root.$digest();
180180
expect(root.b).toEqual(1);
181181
expect(root.c).toEqual(1);
182182
expect(root.d).toEqual(1);
@@ -211,7 +211,7 @@ describe('Scope', function(){
211211
root.$watch('b', function(){ log += 'b'; });
212212
root.$digest();
213213
log = '';
214-
expect(root.$digest()).toEqual(0);
214+
root.$digest();
215215
expect(log).toEqual('');
216216
});
217217

0 commit comments

Comments
 (0)