Web Locks API
lastmod 2024-11-18created 2024-11-181 edits
The Web Locks API allows scripts running in one tab or worker to asynchronously acquire a lock, hold it while work is performed, then release it. While held, no other script executing in the same origin can acquire the same lock, which allows a web app running in multiple tabs or workers to coordinate work and the use of resources.
Features
- The Web Locks API lets a single tab or web worker asynchronously acquire a lock, perform work, and then release the lock
- While a lock is held, no other script in the same origin can acquire the same lock, so resources can be safely coordinated across multiple tabs or workers
- Available only in a Secure Context (HTTPS), and usable in Web Workers
Key concepts and usage
- A lock is an abstract resource identified by a name defined by the web application
- For example, when multiple tabs sync IndexedDB with the network, a lock named “my_net_db_sync” can be used so that only one tab performs the sync at a time
- Usage flow:
- Request the lock
- Perform the asynchronous work
- The lock is released automatically when the work completes
Example code
navigator.locks.request("my_resource", async (lock) => {
await do_something();
await do_something_else();
});
- While the lock is held, other requests for the same lock are queued, and the first request is processed once the lock is released
Options
- mode: The default mode is “exclusive”; “shared” mode is also available. “exclusive” allows only one request, “shared” can allow many
- ifAvailable: The request fails if the lock cannot be acquired immediately, and the callback is invoked with null
- steal: Releases any existing lock with the same name and processes the new request first
- signal: The request can be aborted through an AbortSignal (e.g., to implement a timeout)
Monitoring
-
navigator.locks.query()can be used to query the lock state for the current origin - Useful for debugging; shows which locks are held and which locks have been requested
Advanced usage
- To explicitly control when the asynchronous work completes, a Promise can be returned
let resolve;
const p = new Promise((res) => { resolve = res });
navigator.locks.request("my_resource", (lock) => p);
- The lock is released when resolve() is called
Avoiding deadlock
- A deadlock is a situation where different requests conflict because of ordering and none can make progress
- For example, if tab 1 holds lock A and tab 2 holds lock B, and then tab 1 requests lock B while tab 2 requests lock A, they wait on each other
- To prevent this:
- Do not nest lock requests
- Make lock requests in a consistent order
- Set a timeout to abort the request
Interfaces
- Lock: Provides the name and mode of a requested lock
- LockManager: Provides methods for requesting new locks and querying existing locks
- An instance can be obtained via navigator.locks
- WorkerNavigator.locks is available in Web Workers
Specification and browser support
- Specification: Web Locks API
- Browser compatibility: Supported only in some browsers; support in current browsers can be checked on MDN
GN⁺'s opinion
- The Web Locks API is useful for solving resource synchronization problems in asynchronous environments
- Deadlocks can occur, so care is needed when using it, and safeguards such as timeouts should be considered
- Shared mode can improve performance for read-only work, but race conditions still need careful review
- This API can serve as an alternative for solving the synchronization issues of existing localStorage or IndexedDB