mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Pause refresh when page is hidden (#177693)
## Summary close https://github.com/elastic/kibana/issues/1878 Pauses auto-refresh when a page is not visible. I tested and didn't notice any issues, but looking for more testing help ## Release Notes Auto-refresh pauses when the page is not visible.
This commit is contained in:
parent
c970b395d5
commit
b635674a67
4 changed files with 93 additions and 2 deletions
|
@ -203,3 +203,39 @@ test('calling older done() is ignored', () => {
|
|||
jest.advanceTimersByTime(501);
|
||||
expect(fn1).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('pauses if page is not visible', () => {
|
||||
let mockPageVisibility: DocumentVisibilityState = 'visible';
|
||||
jest.spyOn(document, 'visibilityState', 'get').mockImplementation(() => mockPageVisibility);
|
||||
|
||||
const { loop$, start, stop } = createAutoRefreshLoop();
|
||||
|
||||
const fn = jest.fn((done) => done());
|
||||
loop$.subscribe(fn);
|
||||
|
||||
jest.advanceTimersByTime(5000);
|
||||
expect(fn).not.toBeCalled();
|
||||
|
||||
start(1000);
|
||||
|
||||
jest.advanceTimersByTime(1001);
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
|
||||
mockPageVisibility = 'hidden';
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
|
||||
jest.advanceTimersByTime(1001);
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
|
||||
mockPageVisibility = 'visible';
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
expect(fn).toHaveBeenCalledTimes(2);
|
||||
|
||||
jest.advanceTimersByTime(1001);
|
||||
expect(fn).toHaveBeenCalledTimes(3);
|
||||
|
||||
stop();
|
||||
|
||||
jest.advanceTimersByTime(5000);
|
||||
expect(fn).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
|
||||
import { defer, Subject } from 'rxjs';
|
||||
import { finalize, map } from 'rxjs/operators';
|
||||
import { finalize, map, delayWhen, filter } from 'rxjs/operators';
|
||||
import { once } from 'lodash';
|
||||
import { createPageVisibility$ } from './page_visibility';
|
||||
|
||||
export type AutoRefreshDoneFn = () => void;
|
||||
|
||||
|
@ -18,6 +19,8 @@ export type AutoRefreshDoneFn = () => void;
|
|||
* When auto refresh loop emits, it won't continue automatically,
|
||||
* until each subscriber calls received `done` function.
|
||||
*
|
||||
* Also, it will pause when the page is not visible.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const createAutoRefreshLoop = () => {
|
||||
|
@ -51,6 +54,12 @@ export const createAutoRefreshLoop = () => {
|
|||
_timeoutHandle = -1;
|
||||
}
|
||||
|
||||
const pageVisible$ = createPageVisibility$().pipe(
|
||||
filter((visibility) => visibility === 'visible')
|
||||
);
|
||||
|
||||
const tickWhenVisible$ = tick.pipe(delayWhen(() => pageVisible$));
|
||||
|
||||
return {
|
||||
stop: () => {
|
||||
_timeout = 0;
|
||||
|
@ -65,7 +74,7 @@ export const createAutoRefreshLoop = () => {
|
|||
loop$: defer(() => {
|
||||
subscribersCount++;
|
||||
start(); // restart the loop on a new subscriber
|
||||
return tick.pipe(map((doneCb) => once(doneCb))); // each subscriber allowed to call done only once
|
||||
return tickWhenVisible$.pipe(map((doneCb) => once(doneCb))); // each subscriber allowed to call done only once
|
||||
}).pipe(
|
||||
finalize(() => {
|
||||
subscribersCount--;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { createPageVisibility$ } from './page_visibility';
|
||||
|
||||
let mockPageVisibility: DocumentVisibilityState = 'visible';
|
||||
jest.spyOn(document, 'visibilityState', 'get').mockImplementation(() => mockPageVisibility);
|
||||
|
||||
test('createPageVisibility$ returns an observable that emits visibility state', () => {
|
||||
const pageVisibility$ = createPageVisibility$();
|
||||
|
||||
const fn = jest.fn();
|
||||
pageVisibility$.subscribe(fn);
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
expect(fn).toHaveBeenLastCalledWith('visible');
|
||||
|
||||
mockPageVisibility = 'hidden';
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(2);
|
||||
expect(fn).toHaveBeenLastCalledWith('hidden');
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { fromEvent, Observable } from 'rxjs';
|
||||
import { map, shareReplay, startWith } from 'rxjs/operators';
|
||||
|
||||
export function createPageVisibility$(): Observable<DocumentVisibilityState> {
|
||||
return fromEvent(document, 'visibilitychange').pipe(
|
||||
startWith(document.visibilityState),
|
||||
map(() => document.visibilityState),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue