@@ -29,7 +29,11 @@ export type WrappedWorkerConnectionOptions<Config extends ResolvedWebSQLOpenOpti
2929export class WorkerWrappedAsyncDatabaseConnection < Config extends ResolvedWebSQLOpenOptions = ResolvedWebSQLOpenOptions >
3030 implements AsyncDatabaseConnection
3131{
32- constructor ( protected options : WrappedWorkerConnectionOptions < Config > ) { }
32+ protected lockAbortController : AbortController ;
33+
34+ constructor ( protected options : WrappedWorkerConnectionOptions < Config > ) {
35+ this . lockAbortController = new AbortController ( ) ;
36+ }
3337
3438 protected get baseConnection ( ) {
3539 return this . options . baseConnection ;
@@ -44,6 +48,45 @@ export class WorkerWrappedAsyncDatabaseConnection<Config extends ResolvedWebSQLO
4448 */
4549 async shareConnection ( ) : Promise < SharedConnectionWorker > {
4650 const { identifier, remote } = this . options ;
51+ /**
52+ * Hold a navigator lock in order to avoid features such as Chrome's frozen tabs,
53+ * or Edge's sleeping tabs from pausing the thread for this connection.
54+ * This promise resolves once a lock is obtained.
55+ * This lock will be held as long as this connection is open.
56+ * The `shareConnection` method should not be called on multiple tabs concurrently.
57+ */
58+ await new Promise < void > ( ( resolve , reject ) =>
59+ navigator . locks
60+ . request (
61+ `shared-connection-${ this . options . identifier } ` ,
62+ {
63+ signal : this . lockAbortController . signal
64+ } ,
65+ async ( ) => {
66+ resolve ( ) ;
67+
68+ // Free the lock when the connection is already closed.
69+ if ( this . lockAbortController . signal . aborted ) {
70+ return ;
71+ }
72+
73+ // Hold the lock while the shared connection is in use.
74+ await new Promise < void > ( ( releaseLock ) => {
75+ this . lockAbortController . signal . addEventListener ( 'abort' , ( ) => {
76+ releaseLock ( ) ;
77+ } ) ;
78+ } ) ;
79+ }
80+ )
81+ // We aren't concerned with abort errors here
82+ . catch ( ( ex ) => {
83+ if ( ex . name == 'AbortError' ) {
84+ resolve ( ) ;
85+ } else {
86+ reject ( ex ) ;
87+ }
88+ } )
89+ ) ;
4790
4891 const newPort = await remote [ Comlink . createEndpoint ] ( ) ;
4992 return { port : newPort , identifier } ;
@@ -58,6 +101,8 @@ export class WorkerWrappedAsyncDatabaseConnection<Config extends ResolvedWebSQLO
58101 }
59102
60103 async close ( ) : Promise < void > {
104+ // Abort any pending lock requests.
105+ this . lockAbortController . abort ( ) ;
61106 await this . baseConnection . close ( ) ;
62107 this . options . remote [ Comlink . releaseProxy ] ( ) ;
63108 this . options . onClose ?.( ) ;
0 commit comments