-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Summary
I would like to propose an additional overload of navigator.locks.request() that returns a Lock-like object when called without a callback function. This would allow developers to manually release the lock or use JavaScript’s await using (AsyncDisposable) syntax for automatic cleanup.
Motivation
Currently, the Web Locks API usage looks like this:
await navigator.locks.request("name", async lock => {
// work
});While this callback style is convenient in some scenarios, it can be limiting in others, such as:
- When you want to pass the lock object around different scopes.
- When using libraries like
disposable-lockthat rely on explicit lock objects and automatic disposal patterns. - When you want to integrate with ECMAScript
await using/AsyncDisposablesyntax for safer automatic cleanup.
The desired additional usage would be:
// Case 1: explicit release
const lock = await navigator.locks.request("name");
// do work...
await lock.release();Or:
// Case 2: using / auto-release
{
await using lock = await navigator.locks.request("name");
// do work...
}
// lock is automatically releasedProposed API
interface LockManager {
request(name: string, options?: { ifAvailable?: boolean }): Promise<DisposableLock | null>;
}Where DisposableLock could be defined as:
interface DisposableLock {
readonly name: string;
readonly mode: LockMode;
release(): Promise<void>;
[Symbol.asyncDispose](): Promise<void>; // for ECMAScript using support
}This allows developers to safely use await using even if the lock was not obtained.
Potential Concerns / Considerations
- Backward compatibility with the existing callback-based API
- Ensuring locks are always released even if the user forgets
release() - Aligning the behavior with current lifetime rules in the Web Locks API
- Interaction with reentrancy and contention handling
- Handling
ifAvailable: truecases consistently with bothDisposableLockand null
References
- Web Locks API Editor’s Draft
disposable-locknpm package- ECMAScript
await using/AsyncDisposableproposal: TC39 AsyncDisposable
Update:
Based on recent feedback from TC39 regarding AsyncDisposable, disposable-lock has been updated so that navigator.locks.request() now returns:
- a
ReleasableLockobject when the lock is successfully acquired, or nullwhen the lock could not be obtained (e.g.,ifAvailable: true).
This ensures compatibility with await using and aligns with the language-level guidance that await using x = null works safely.
Example usage:
{
await using lock = await navigator.locks.request("name", { ifAvailable: true });
if (lock) {
// lock was acquired, work can proceed
} else {
// lock was not acquired, safe to skip
}
}