Skip to content

Commit

Permalink
fix($rootScope): prevent infinite $digest loop by also checking if as…
Browse files Browse the repository at this point in the history
…yncQueue is empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise. The problem is that $digest does not
decrement ttl unless it finds dirty changes; it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the condition for terminating the $digest loop.

Closes angular#2622
  • Loading branch information
sinelaw committed Dec 30, 2013
1 parent 80e7a45 commit 6225262
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/ng/rootScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ function $RootScopeProvider(){

// `break traverseScopesLoop;` takes us to here

if(dirty && !(ttl--)) {
if((dirty || asyncQueue.length) && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' +
Expand Down
27 changes: 26 additions & 1 deletion test/ng/rootScopeSpec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

describe('Scope', function() {
ddescribe('Scope', function() {

beforeEach(module(provideLog));

Expand Down Expand Up @@ -258,6 +258,31 @@ describe('Scope', function() {
}));


iit('should prevent infinite loop when creating and resolving a promise in a watched expression', function() {
module(function($rootScopeProvider) {
$rootScopeProvider.digestTtl(10);
});
inject(function($rootScope, $q) {
var d = $q.defer();

d.resolve('Hello, world.');
$rootScope.$watch(function () {
var $d2 = $q.defer();
$d2.resolve('Goodbye, cruel world.');
$d2.promise.then(function () { });
return d.promise;
}, function () { return 0; });

expect(function() {
$rootScope.$digest();
}).toThrowMinErr('$rootScope', 'infdig', '10 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: []');

expect($rootScope.$$phase).toBeNull();
});
});


it('should not fire upon $watch registration on initial $digest', inject(function($rootScope) {
var log = '';
$rootScope.a = 1;
Expand Down

0 comments on commit 6225262

Please sign in to comment.