aboutsummaryrefslogtreecommitdiffstats
path: root/test/ng/rootScopeSpec.js
diff options
context:
space:
mode:
authorKarl Seamon2013-12-03 19:16:08 -0500
committerIgor Minar2013-12-05 15:37:37 -0800
commitd070450cd2b3b3a3aa34b69d3fa1f4cc3be025dd (patch)
tree7e92e3b9f74e53e301ef1e86cb899e1feb76baa3 /test/ng/rootScopeSpec.js
parent09648e4888896948b733febb9c8652a36f8a22dd (diff)
downloadangular.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.js76
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']);
+ }));
+ });
});