Skip to content
Permalink
Browse files

perf($rootScope): remove history event handler when app is torn down

Remember the popstate and hashchange handler registered with window
when the application bootstraps, and remove it when the application
is torn down

Closes #9897
Closes #9905
  • Loading branch information...
randombk authored and petebacondarwin committed Nov 4, 2014
1 parent 79fa7dd commit d996305b4470f80fbb1cbddf54b7d10ffbb6ab47
Showing with 40 additions and 0 deletions.
  1. +10 −0 src/ng/browser.js
  2. +5 −0 src/ng/rootScope.js
  3. +1 −0 src/ngMock/angular-mocks.js
  4. +17 −0 test/ng/browserSpecs.js
  5. +7 −0 test/ng/rootScopeSpec.js
@@ -264,6 +264,16 @@ function Browser(window, document, $log, $sniffer) {
return callback;
};

/**
* @private
* Remove popstate and hashchange handler from window.
*
* NOTE: this api is intended for use only by $rootScope.
*/
self.$$applicationDestroyed = function() {
jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
};

/**
* Checks whether the url has changed outside of Angular.
* Needs to be exported to be able to check for changes that have been done in sync,
@@ -878,6 +878,11 @@ function $RootScopeProvider() {
this.$broadcast('$destroy');
this.$$destroyed = true;

if (this === $rootScope) {
//Remove handlers attached to window when $rootScope is removed
$browser.$$applicationDestroyed();
}

incrementWatchersCount(this, -this.$$watchersCount);
for (var eventName in this.$$listenerCount) {
decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
@@ -57,6 +57,7 @@ angular.mock.$Browser = function() {
return listener;
};

self.$$applicationDestroyed = angular.noop;
self.$$checkUrlChange = angular.noop;

self.deferredFns = [];
@@ -647,6 +647,23 @@ describe('browser', function() {
};
}
});


it("should stop calling callbacks when application has been torn down", function() {
sniffer.history = true;
browser.onUrlChange(callback);
fakeWindow.location.href = 'http://server/new';

browser.$$applicationDestroyed();

fakeWindow.fire('popstate');
expect(callback).not.toHaveBeenCalled();

fakeWindow.fire('hashchange');
fakeWindow.setTimeout.flush();
expect(callback).not.toHaveBeenCalled();
});

});


@@ -1048,6 +1048,13 @@ describe('Scope', function() {
}));


it('should call $browser.$$applicationDestroyed when destroying rootScope', inject(function($rootScope, $browser) {
spyOn($browser, '$$applicationDestroyed');
$rootScope.$destroy();
expect($browser.$$applicationDestroyed).toHaveBeenCalledOnce();
}));


it('should remove first', inject(function($rootScope) {
first.$destroy();
$rootScope.$digest();

0 comments on commit d996305

Please sign in to comment.
You can’t perform that action at this time.