Skip to content

Commit 0d056cb

Browse files
committed
perf($animate): listen for document visibility changes
Accessing the document for the hidden state is costly for platforms like Electron. Closes angular#14066
1 parent 2310e10 commit 0d056cb

File tree

6 files changed

+34
-21
lines changed

6 files changed

+34
-21
lines changed

src/AngularPublic.js

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
$ControllerProvider,
6666
$DateProvider,
6767
$DocumentProvider,
68+
$$IsDocumentHiddenProvider,
6869
$ExceptionHandlerProvider,
6970
$FilterProvider,
7071
$$ForceReflowProvider,
@@ -227,6 +228,7 @@ function publishExternalAPI(angular) {
227228
$cacheFactory: $CacheFactoryProvider,
228229
$controller: $ControllerProvider,
229230
$document: $DocumentProvider,
231+
$$isDocumentHidden: $$IsDocumentHiddenProvider,
230232
$exceptionHandler: $ExceptionHandlerProvider,
231233
$filter: $FilterProvider,
232234
$$forceReflow: $$ForceReflowProvider,

src/ng/animateRunner.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ var $$AnimateAsyncRunFactoryProvider = function() {
2828
};
2929

3030
var $$AnimateRunnerFactoryProvider = function() {
31-
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
32-
function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
31+
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
32+
function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) {
3333

3434
var INITIAL_STATE = 0;
3535
var DONE_PENDING_STATE = 1;
@@ -81,11 +81,7 @@ var $$AnimateRunnerFactoryProvider = function() {
8181

8282
this._doneCallbacks = [];
8383
this._tick = function(fn) {
84-
var doc = $document[0];
85-
86-
// the document may not be ready or attached
87-
// to the module for some internal tests
88-
if (doc && doc.hidden) {
84+
if ($$isDocumentHidden()) {
8985
timeoutTick(fn);
9086
} else {
9187
rafTick(fn);

src/ng/document.js

+16
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,19 @@ function $DocumentProvider() {
3030
return jqLite(window.document);
3131
}];
3232
}
33+
34+
35+
function $$IsDocumentHiddenProvider() {
36+
this.$get = ['$document', function($document) {
37+
var doc = $document[0];
38+
var hidden = doc && doc.hidden;
39+
40+
$document.on('visibilitychange', function() {
41+
hidden = doc.hidden;
42+
});
43+
44+
return function() {
45+
return hidden;
46+
};
47+
}];
48+
}

src/ngAnimate/animateQueue.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
102102

103103
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
104104
'$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
105+
'$$isDocumentHidden',
105106
function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
106-
$$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {
107+
$$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow,
108+
$$isDocumentHidden) {
107109

108110
var activeAnimationsLookup = new $$HashMap();
109111
var disabledElementsLookup = new $$HashMap();
@@ -374,7 +376,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
374376
// past this point if not enabled
375377
// Animations are also disabled if the document is currently hidden (page is not visible
376378
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
377-
var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
379+
var skipAnimations = !animationsEnabled || $$isDocumentHidden() || disabledElementsLookup.get(node);
378380
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
379381
var hasExistingAnimation = !!existingAnimation.state;
380382

test/ng/animateRunnerSpec.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,13 @@ describe("$$AnimateRunner", function() {
163163
}));
164164

165165
it("should use timeouts to trigger async operations when the document is hidden", function() {
166-
var doc;
166+
var hidden = true;
167167

168168
module(function($provide) {
169-
doc = jqLite({
170-
body: document.body,
171-
hidden: true
169+
170+
$provide.value('$$isDocumentHidden', function() {
171+
return hidden;
172172
});
173-
$provide.value('$document', doc);
174173
});
175174

176175
inject(function($$AnimateRunner, $rootScope, $$rAF, $timeout) {
@@ -184,7 +183,7 @@ describe("$$AnimateRunner", function() {
184183
$timeout.flush();
185184
expect(spy).toHaveBeenCalled();
186185

187-
doc[0].hidden = false;
186+
hidden = false;
188187

189188
spy = jasmine.createSpy();
190189
runner = new $$AnimateRunner();

test/ngAnimate/animateSpec.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,12 @@ describe("animations", function() {
157157
}));
158158

159159
it("should skip animations entirely if the document is hidden", function() {
160-
var doc;
160+
var hidden = true;
161161

162162
module(function($provide) {
163-
doc = jqLite({
164-
body: document.body,
165-
hidden: true
163+
$provide.value('$$isDocumentHidden', function() {
164+
return hidden;
166165
});
167-
$provide.value('$document', doc);
168166
});
169167

170168
inject(function($animate, $rootScope) {
@@ -173,7 +171,7 @@ describe("animations", function() {
173171
expect(capturedAnimation).toBeFalsy();
174172
expect(element[0].parentNode).toEqual(parent[0]);
175173

176-
doc[0].hidden = false;
174+
hidden = false;
177175

178176
$animate.leave(element);
179177
$rootScope.$digest();

0 commit comments

Comments
 (0)