diff options
| author | Misko Hevery | 2012-05-23 14:49:01 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2012-05-23 16:01:20 -0700 | 
| commit | 989446eceee697b15ecb5df1f491dfbcff352256 (patch) | |
| tree | d9b22e53d9014924019f17c9fe3b2b5d85838592 | |
| parent | 5214c1d0cbd8473e1f5dd3894f1fcbecd89bc8af (diff) | |
| download | angular.js-989446eceee697b15ecb5df1f491dfbcff352256.tar.bz2 | |
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
| -rw-r--r-- | src/ng/rootScope.js | 34 | ||||
| -rw-r--r-- | test/ng/rootScopeSpec.js | 23 | 
2 files changed, 45 insertions, 12 deletions
diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index bb12362b..81c9ee78 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -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(); + +    return $rootScope; -    function flagPhase(scope, phase) { -      var root = scope.$root; -      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); diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index 9d343b08..934541c1 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -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) {  | 
