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

Commit

Permalink
feat(scope): better logging of infinite digest error
Browse files Browse the repository at this point in the history
Feedback team has often problems debugging inifinite digest errors, this change
should reveal info about what watchers are causing the infinite loop
  • Loading branch information
IgorMinar committed Oct 31, 2011
1 parent 615841a commit ef875ad
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
17 changes: 14 additions & 3 deletions src/Scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ Scope.prototype = {
watcher = {
fn: listenFn,
last: Number.NaN, // NaN !== NaN. We used this to force $watch to fire on first run.
get: get
get: get,
exp: watchExp
};

if (!array) {
Expand Down Expand Up @@ -325,7 +326,8 @@ Scope.prototype = {
asyncQueue,
length,
dirty, ttl = 100,
next, current, target = this;
next, current, target = this,
watchLog = [];

if (target.$$phase) {
throw Error(target.$$phase + ' already in progress');
Expand Down Expand Up @@ -356,6 +358,14 @@ Scope.prototype = {
dirty = true;
watch.last = copy(value);
watch.fn(current, value, last);
if (ttl < 5) {
if (!watchLog[4-ttl]) watchLog[4-ttl] = [];
if (isFunction(watch.exp)) {
watchLog[4-ttl].push('fn: ' + (watch.exp.name || watch.exp.toString()));
} else {
watchLog[4-ttl].push(watch.exp);
}
}
}
} catch (e) {
current.$service('$exceptionHandler')(e);
Expand All @@ -376,7 +386,8 @@ Scope.prototype = {
} while ((current = next));

if(!(ttl--)) {
throw Error('100 $digest() iterations reached. Aborting!');
throw Error('100 $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
}
} while (dirty);
},
Expand Down
28 changes: 24 additions & 4 deletions test/ScopeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,34 @@ describe('Scope', function() {
});


it('should prevent infinite recursion', function() {
root.$watch('a', function(self, v){self.b++;});
root.$watch('b', function(self, v){self.a++;});
it('should prevent infinite recursion and print watcher expression', function() {
root.$watch('a', function(self){self.b++;});
root.$watch('b', function(self){self.a++;});
root.a = root.b = 0;

expect(function() {
root.$digest();
}).toThrow('100 $digest() iterations reached. Aborting!');
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: ' +
'[["a","b"],["a","b"],["a","b"],["a","b"],["a","b"]]');
});


it('should prevent infinite recurcion and print print watcher function name or body',
function() {
root.$watch(function watcherA() {return root.a;}, function(self){self.b++;});
root.$watch(function() {return root.b;}, function(self){self.a++;});
root.a = root.b = 0;

expect(function() {
root.$digest();
}).toThrow('100 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: ' +
'[["fn: watcherA","fn: function () {return root.b;}"],'+
'["fn: watcherA","fn: function () {return root.b;}"],'+
'["fn: watcherA","fn: function () {return root.b;}"],'+
'["fn: watcherA","fn: function () {return root.b;}"],'+
'["fn: watcherA","fn: function () {return root.b;}"]]');
});


Expand Down

0 comments on commit ef875ad

Please sign in to comment.