mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-12 22:45:52 +08:00
feat(scope): better logging of infinite digest error
Feedback team has often problems debugging inifinite digest errors, this change should reveal info about what watchers are causing the infinite loop
This commit is contained in:
17
src/Scope.js
17
src/Scope.js
@@ -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) {
|
||||
@@ -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');
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -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;}"]]');
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user