fix($rootScope): TTL exception does not clear $$phase

When $digest() throws infinite digest exception it
does not properly clear the $phase leaving the scope
in an inconsistent state.

Closes #979
This commit is contained in:
Misko Hevery 2012-05-23 14:49:01 -07:00
parent 5214c1d0cb
commit 989446ecee
2 changed files with 45 additions and 12 deletions

View file

@ -372,7 +372,7 @@ function $RootScopeProvider(){
watchLog = [],
logIdx, logMsg;
flagPhase(target, '$digest');
beginPhase('$digest');
do {
dirty = false;
@ -429,12 +429,13 @@ function $RootScopeProvider(){
} while ((current = next));
if(dirty && !(ttl--)) {
clearPhase();
throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
}
} while (dirty || asyncQueue.length);
this.$root.$$phase = null;
clearPhase();
},
@ -469,7 +470,7 @@ function $RootScopeProvider(){
* perform any necessary cleanup.
*/
$destroy: function() {
if (this.$root == this) return; // we can't remove the root node;
if ($rootScope == this) return; // we can't remove the root node;
var parent = this.$parent;
this.$broadcast('$destroy');
@ -586,13 +587,18 @@ function $RootScopeProvider(){
*/
$apply: function(expr) {
try {
flagPhase(this, '$apply');
beginPhase('$apply');
return this.$eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
this.$root.$$phase = null;
this.$root.$digest();
clearPhase();
try {
$rootScope.$digest();
} catch (e) {
$exceptionHandler(e);
throw e;
}
}
},
@ -754,18 +760,22 @@ function $RootScopeProvider(){
}
};
var $rootScope = new Scope();
function flagPhase(scope, phase) {
var root = scope.$root;
return $rootScope;
if (root.$$phase) {
throw Error(root.$$phase + ' already in progress');
function beginPhase(phase) {
if ($rootScope.$$phase) {
throw Error($rootScope.$$phase + ' already in progress');
}
root.$$phase = phase;
$rootScope.$$phase = phase;
}
return new Scope();
function clearPhase() {
$rootScope.$$phase = null;
}
function compileToFn(exp, name) {
var fn = $parse(exp);

View file

@ -210,6 +210,8 @@ describe('Scope', function() {
'["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' +
'["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' +
'["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]');
expect($rootScope.$$phase).toBeNull();
});
});
@ -492,6 +494,27 @@ describe('Scope', function() {
});
it('should log exceptions from $digest', function() {
module(function($rootScopeProvider, $exceptionHandlerProvider) {
$rootScopeProvider.digestTtl(2);
$exceptionHandlerProvider.mode('log');
});
inject(function($rootScope, $exceptionHandler) {
$rootScope.$watch('a', function() {$rootScope.b++;});
$rootScope.$watch('b', function() {$rootScope.a++;});
$rootScope.a = $rootScope.b = 0;
expect(function() {
$rootScope.$apply();
}).toThrow();
expect($exceptionHandler.errors[0]).toBeDefined();
expect($rootScope.$$phase).toBeNull();
});
});
describe('exceptions', function() {
var log;
beforeEach(module(function($exceptionHandlerProvider) {