Skip to content

Commit 2e6e07c

Browse files
authored
feat: wrap navigator.locks.request with plain promise to help zone.js (#989)
Wraps the `navigator.locks.request()` function with a plain Promise as libraries such as zone.js patch this object to track execution context. It appears that this browser API uses a native promise that's not patched, causing the tracking context to be lost. It is believed that wrapping this non-zone.js Promise returned by the browser with a promise that's patched by zone.js can help the situation. Related: - supabase/supabase-js#936 - #830
1 parent f808e7a commit 2e6e07c

File tree

1 file changed

+60
-51
lines changed

1 file changed

+60
-51
lines changed

src/lib/locks.ts

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -78,68 +78,77 @@ export async function navigatorLock<R>(
7878

7979
// MDN article: https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request
8080

81-
return await globalThis.navigator.locks.request(
82-
name,
83-
acquireTimeout === 0
84-
? {
85-
mode: 'exclusive',
86-
ifAvailable: true,
87-
}
88-
: {
89-
mode: 'exclusive',
90-
signal: abortController.signal,
91-
},
92-
async (lock) => {
93-
if (lock) {
94-
if (internals.debug) {
95-
console.log('@supabase/gotrue-js: navigatorLock: acquired', name, lock.name)
96-
}
97-
98-
try {
99-
return await fn()
100-
} finally {
101-
if (internals.debug) {
102-
console.log('@supabase/gotrue-js: navigatorLock: released', name, lock.name)
81+
// Wrapping navigator.locks.request() with a plain Promise is done as some
82+
// libraries like zone.js patch the Promise object to track the execution
83+
// context. However, it appears that most browsers use an internal promise
84+
// implementation when using the navigator.locks.request() API causing them
85+
// to lose context and emit confusing log messages or break certain features.
86+
// This wrapping is believed to help zone.js track the execution context
87+
// better.
88+
return await Promise.resolve().then(() =>
89+
globalThis.navigator.locks.request(
90+
name,
91+
acquireTimeout === 0
92+
? {
93+
mode: 'exclusive',
94+
ifAvailable: true,
10395
}
104-
}
105-
} else {
106-
if (acquireTimeout === 0) {
96+
: {
97+
mode: 'exclusive',
98+
signal: abortController.signal,
99+
},
100+
async (lock) => {
101+
if (lock) {
107102
if (internals.debug) {
108-
console.log('@supabase/gotrue-js: navigatorLock: not immediately available', name)
103+
console.log('@supabase/gotrue-js: navigatorLock: acquired', name, lock.name)
109104
}
110105

111-
throw new NavigatorLockAcquireTimeoutError(
112-
`Acquiring an exclusive Navigator LockManager lock "${name}" immediately failed`
113-
)
106+
try {
107+
return await fn()
108+
} finally {
109+
if (internals.debug) {
110+
console.log('@supabase/gotrue-js: navigatorLock: released', name, lock.name)
111+
}
112+
}
114113
} else {
115-
if (internals.debug) {
116-
try {
117-
const result = await globalThis.navigator.locks.query()
114+
if (acquireTimeout === 0) {
115+
if (internals.debug) {
116+
console.log('@supabase/gotrue-js: navigatorLock: not immediately available', name)
117+
}
118118

119-
console.log(
120-
'@supabase/gotrue-js: Navigator LockManager state',
121-
JSON.stringify(result, null, ' ')
122-
)
123-
} catch (e: any) {
124-
console.warn(
125-
'@supabase/gotrue-js: Error when querying Navigator LockManager state',
126-
e
127-
)
119+
throw new NavigatorLockAcquireTimeoutError(
120+
`Acquiring an exclusive Navigator LockManager lock "${name}" immediately failed`
121+
)
122+
} else {
123+
if (internals.debug) {
124+
try {
125+
const result = await globalThis.navigator.locks.query()
126+
127+
console.log(
128+
'@supabase/gotrue-js: Navigator LockManager state',
129+
JSON.stringify(result, null, ' ')
130+
)
131+
} catch (e: any) {
132+
console.warn(
133+
'@supabase/gotrue-js: Error when querying Navigator LockManager state',
134+
e
135+
)
136+
}
128137
}
129-
}
130138

131-
// Browser is not following the Navigator LockManager spec, it
132-
// returned a null lock when we didn't use ifAvailable. So we can
133-
// pretend the lock is acquired in the name of backward compatibility
134-
// and user experience and just run the function.
135-
console.warn(
136-
'@supabase/gotrue-js: Navigator LockManager returned a null lock when using #request without ifAvailable set to true, it appears this browser is not following the LockManager spec https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request'
137-
)
139+
// Browser is not following the Navigator LockManager spec, it
140+
// returned a null lock when we didn't use ifAvailable. So we can
141+
// pretend the lock is acquired in the name of backward compatibility
142+
// and user experience and just run the function.
143+
console.warn(
144+
'@supabase/gotrue-js: Navigator LockManager returned a null lock when using #request without ifAvailable set to true, it appears this browser is not following the LockManager spec https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request'
145+
)
138146

139-
return await fn()
147+
return await fn()
148+
}
140149
}
141150
}
142-
}
151+
)
143152
)
144153
}
145154

0 commit comments

Comments
 (0)