# Web Locks API

The Web Locks API allows scripts running in one tab or worker to asynchronously acquire a lock, hold it while work is performed, and then release it. This is crucial for coordinating the use of shared resources (like IndexedDB, LocalStorage, or network resources) across multiple tabs or workers to prevent race conditions.

## 1. The Concept

If you have two tabs open for the same web app, and both try to write to the same IndexedDB record simultaneously, data corruption can occur. The Web Locks API provides a standard way to ensure that only one tab performs a critical operation at a time.

## 2. Requesting a Lock

The API is accessed via `navigator.locks.request()`.

**Syntax:** `navigator.locks.request(name, [options], callback)`

The lock is automatically released when the callback function returns (or the Promise returned by the callback resolves).

```javascript
// Request an exclusive lock named "my_resource"
navigator.locks.request('my_resource', async (lock) => {
  // The lock has been acquired.
  console.log('Lock acquired');
  
  // Perform work (e.g., write to database)
  await doSomethingCritical();
  
  console.log('Lock released');
});
```

## 3. Lock Modes

There are two modes for locks:

*   **`exclusive`** (Default): Only one script can hold the lock at a time. Good for writing.
*   **`shared`**: Multiple scripts can hold the lock at the same time, but no one can hold an exclusive lock while shared locks are active. Good for reading.

```javascript
// Tab A: Reading (Shared)
navigator.locks.request('db_access', { mode: 'shared' }, async (lock) => {
  // Can run simultaneously with Tab B
  await readData();
});

// Tab B: Reading (Shared)
navigator.locks.request('db_access', { mode: 'shared' }, async (lock) => {
  // Can run simultaneously with Tab A
  await readData();
});

// Tab C: Writing (Exclusive)
navigator.locks.request('db_access', { mode: 'exclusive' }, async (lock) => {
  // Waits for Tab A and Tab B to finish
  await writeData();
});
```

## 4. Options

*   **`mode`**: `'exclusive'` or `'shared'`.
*   **`ifAvailable`**: If `true`, the request will fail (return `null`) immediately if the lock cannot be granted, instead of waiting in a queue.
*   **`steal`**: If `true`, any existing locks are released, and this request is granted. Use with extreme caution (e.g., for recovery from a hung state).
*   **`signal`**: An `AbortSignal` to abort the lock request while it is queued.

```javascript
navigator.locks.request('resource', { ifAvailable: true }, async (lock) => {
  if (!lock) {
    console.log('Lock is currently busy, try again later.');
    return;
  }
  // Do work...
});
```

[[programming/javascript/vanilla/javascript]]
[[programming/javascript/vanilla/promises-async-await]]
[[programming/javascript/vanilla/indexeddb]]