diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 1bb128695f8d..39cb9471db58 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -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' + diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index 3677ccc8729e..8591ce64c013 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -1,6 +1,6 @@ 'use strict'; -describe('Scope', function() { +ddescribe('Scope', function() { beforeEach(module(provideLog)); @@ -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;