diff options
| author | Karl Seamon | 2013-12-03 19:16:08 -0500 | 
|---|---|---|
| committer | Igor Minar | 2013-12-05 15:37:37 -0800 | 
| commit | d070450cd2b3b3a3aa34b69d3fa1f4cc3be025dd (patch) | |
| tree | 7e92e3b9f74e53e301ef1e86cb899e1feb76baa3 /test/ng/rootScopeSpec.js | |
| parent | 09648e4888896948b733febb9c8652a36f8a22dd (diff) | |
| download | angular.js-d070450cd2b3b3a3aa34b69d3fa1f4cc3be025dd.tar.bz2 | |
chore(Scope): short-circuit after dirty-checking last dirty watcher
Stop dirty-checking during $digest after the last dirty watcher has been re-checked.
This prevents unneeded re-checking of the remaining watchers (They were already
checked in the previous iteration), bringing a substantial performance improvement
to the average case run time of $digest.
Closes #5272
Closes #5287
Diffstat (limited to 'test/ng/rootScopeSpec.js')
| -rw-r--r-- | test/ng/rootScopeSpec.js | 76 | 
1 files changed, 76 insertions, 0 deletions
| diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index 287b5356..cc6727c2 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -577,6 +577,82 @@ describe('Scope', function() {          });        });      }); + + +    describe('optimizations', function() { + +      function setupWatches(scope, log) { +        scope.$watch(function() { log('w1'); return scope.w1; }, log.fn('w1action')); +        scope.$watch(function() { log('w2'); return scope.w2; }, log.fn('w2action')); +        scope.$watch(function() { log('w3'); return scope.w3; }, log.fn('w3action')); +        scope.$digest(); +        log.reset(); +      } + + +      it('should check watches only once during an empty digest', inject(function(log, $rootScope) { +        setupWatches($rootScope, log); +        $rootScope.$digest(); +        expect(log).toEqual(['w1', 'w2', 'w3']); +      })); + + +      it('should quit digest early after we check the last watch that was previously dirty', +          inject(function(log, $rootScope) { +        setupWatches($rootScope, log); +        $rootScope.w1 = 'x'; +        $rootScope.$digest(); +        expect(log).toEqual(['w1', 'w1action', 'w2', 'w3', 'w1']); +      })); + + +      it('should not quit digest early if a new watch was added from an existing watch action', +          inject(function(log, $rootScope) { +        setupWatches($rootScope, log); +        $rootScope.$watch(log.fn('w4'), function() { +          log('w4action'); +          $rootScope.$watch(log.fn('w5'), log.fn('w5action')); +        }); +        $rootScope.$digest(); +        expect(log).toEqual(['w1', 'w2', 'w3', 'w4', 'w4action', +                             'w1', 'w2', 'w3', 'w4', 'w5', 'w5action', +                             'w1', 'w2', 'w3', 'w4', 'w5']); +      })); + + +      it('should not quit digest early if an evalAsync task was scheduled from a watch action', +          inject(function(log, $rootScope) { +        setupWatches($rootScope, log); +        $rootScope.$watch(log.fn('w4'), function() { +          log('w4action'); +          $rootScope.$evalAsync(function() { +            log('evalAsync') +          }); +        }); +        $rootScope.$digest(); +        expect(log).toEqual(['w1', 'w2', 'w3', 'w4', 'w4action', 'evalAsync', +                             'w1', 'w2', 'w3', 'w4']); +      })); + + +      it('should quit digest early but not too early when various watches fire', inject(function(log, $rootScope) { +        setupWatches($rootScope, log); +        $rootScope.$watch(function() { log('w4'); return $rootScope.w4; }, function(newVal) { +          log('w4action'); +          $rootScope.w2 = newVal; +        }); + +        $rootScope.$digest(); +        log.reset(); + +        $rootScope.w1 = 'x'; +        $rootScope.w4 = 'x'; +        $rootScope.$digest(); +        expect(log).toEqual(['w1', 'w1action', 'w2', 'w3', 'w4', 'w4action', +                             'w1', 'w2', 'w2action', 'w3', 'w4', +                             'w1', 'w2']); +      })); +    });    }); | 
