Skip to content

Commit 073b93c

Browse files
committed
Use a WebLock to prevent browser tab from sleeping
1 parent a104e2d commit 073b93c

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

src/SignalR/clients/ts/signalr/src/HubConnection.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ILogger, LogLevel } from "./ILogger";
88
import { IRetryPolicy } from "./IRetryPolicy";
99
import { IStreamResult } from "./Stream";
1010
import { Subject } from "./Subject";
11-
import { Arg, getErrorString } from "./Utils";
11+
import { Arg, getErrorString, Platform } from "./Utils";
1212

1313
const DEFAULT_TIMEOUT_IN_MS: number = 30 * 1000;
1414
const DEFAULT_PING_INTERVAL_IN_MS: number = 15 * 1000;
@@ -49,6 +49,7 @@ export class HubConnection {
4949
private _handshakeResolver!: (value?: PromiseLike<{}>) => void;
5050
private _handshakeRejecter!: (reason?: any) => void;
5151
private _stopDuringStartError?: Error;
52+
private _lockResolver!: (value?: PromiseLike<{}>) => void;
5253

5354
private _connectionState: HubConnectionState;
5455
// connectionStarted is tracked independently from connectionState, so we can check if the
@@ -65,6 +66,11 @@ export class HubConnection {
6566
private _timeoutHandle?: any;
6667
private _pingServerHandle?: any;
6768

69+
private _freezeEventListener = () =>
70+
{
71+
this._logger.log(LogLevel.Warning, "The page is being frozen, this will likely lead to the connection being closed and messages being lost.");
72+
};
73+
6874
/** The server timeout in milliseconds.
6975
*
7076
* If this timeout elapses without receiving any messages from the server, the connection will be terminated with an error.
@@ -174,6 +180,27 @@ export class HubConnection {
174180
try {
175181
await this._startInternal();
176182

183+
if (Platform.isBrowser) {
184+
if (document) {
185+
document.addEventListener("freeze", this._freezeEventListener);
186+
}
187+
188+
const promise = new Promise((res) => {
189+
this._lockResolver = res;
190+
});
191+
192+
// Chrome and Edge currently support Web Locks, it's also experimental, so let's be safe and check if the APIs exist
193+
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API
194+
// This should prevent the browsers from sleeping the tab which would close the connection unexpectedly
195+
if (navigator && (navigator as any).locks && (navigator as any).locks.request) {
196+
// Use a 'shared' lock so multiple tabs to the same site can used the same lock
197+
(navigator as any).locks.request('signalr_client_lock', { mode: "shared" }, () => {
198+
// Keep lock until promise is resolved
199+
return promise;
200+
});
201+
}
202+
}
203+
177204
this._connectionState = HubConnectionState.Connected;
178205
this._connectionStarted = true;
179206
this._logger.log(LogLevel.Debug, "HubConnection connected successfully.");
@@ -721,6 +748,13 @@ export class HubConnection {
721748
this._connectionState = HubConnectionState.Disconnected;
722749
this._connectionStarted = false;
723750

751+
this._lockResolver();
752+
if (Platform.isBrowser) {
753+
if (document) {
754+
document.removeEventListener("freeze", this._freezeEventListener);
755+
}
756+
}
757+
724758
try {
725759
this._closedCallbacks.forEach((c) => c.apply(this, [error]));
726760
} catch (e) {

0 commit comments

Comments
 (0)