LockManager: request() メソッド

LockManager インターフェイスの request() メソッドは、名前と性質を指定する引数をとり、Lock オブジェクトを要求します。要求された Lock はコールバックに渡されます。この関数自体は、ロックの解放後にコールバックの結果で解決 (または拒否) され、リクエストが中止された場合は拒否される Promise を返します。

引数 options のプロパティ mode は、"exclusive""shared" のいずれかをとることができます。

一度に 1 個のコードインスタンスのみがロックを確保するべきときは、"exclusive" ロックを要求します。これはタブで実行するコードにもワーカーで実行するコードにも当てはまります。これはリソースへの互いに排他的なアクセスを表します。ある名前の "exclusive" ロックが確保されているときは、同じ名前の他のロックは一切確保できません。

コードの複数のインスタンスがリソースへのアクセスを共有できるときは、"shared" ロックを要求します。ある名前の "shared" ロックが確保されているときは、同じ名前の他の "shared" ロックを獲得することはできますが、その名前の "exclusive" ロックを獲得・確保することができません。

この共有 / 排他ロックのパターンは、読み込みは同時に複数 (それぞれが "shared" ロックを要求する) 行うことを許し、書き込みは 1 個だけ (単一の "exclusive" ロック) 許すなど、データベースのトランザクションのアーキテクチャではよくみられます。これは readers-writer パターンとして知られています。IndexedDB API では、これは同じ意味の "readonly" および "readwrite" トランザクションとして公開されています。

構文

js
request(name, callback)
request(name, options, callback)

引数

name

要求するロックの識別子です。

options 省略可

生成するロックの性質を記述するオブジェクトです。以下の値が有効です。

mode 省略可

"exclusive" または "shared" です。デフォルト値は "exclusive" です。

ifAvailable 省略可

true に設定した場合、ロックが既に確保されていない場合のみロックを獲得できます。ロックを獲得できない場合は、コールバックには Lock のインスタンスではなく null が渡されます。デフォルト値は false です。

steal 省略可

true に設定した場合、同じ名前の既に確保されているロックはすべて解放され、待機中のすべての要求よりも優先してロックを獲得します。デフォルト値は false です。

警告: 使用には注意が必要です! これまでロック内で実行されていたコードの実行は継続し、新しくロックを確保したコードと衝突する可能性があります。

signal 省略可

AbortSignal (AbortControllersignal プロパティ) です。指定され、対応する AbortController が中断された場合、獲得できていないロックの要求は破棄されます。

callback

ロックを獲得したとき呼び出されるメソッドです。ロックはコールバックから返ったとき (または例外が投げられたとき) 自動的に解放されます。通常、コールバックは非同期関数で、この場合はロックは非同期の実行が完全に完了するまで解放されません。

返値

ロックの解放後コールバックの結果で解決 (または拒否) し、要求が中断されると拒否される Promise を返します。

例外

このメソッドは、以下のいずれかの種類の DOMException で拒否される Promise を返す可能性があります。

InvalidStateError DOMException

ドキュメントが完全にアクティブでない環境のとき。

SecurityError DOMException

現在の環境でロックマネージャーが取得できないとき。

NotSupportedError DOMException

name がハイフン (-) で始まるとき、stealifAvailable の両方が true に設定されているとき、signal が設定されておりかつ stealifAvailableいずれかtrue に設定されているとき。

AbortError DOMException

signal が設定されており、中断されたとき。

一般の例

以下の例では、非同期関数をコールバックとして用いる request() メソッドの基本的な使用法を示します。コールバックが呼び出されると、それが帰るまでこのオリジンで実行中の他のコードは my_resource を確保できません。

js
await navigator.locks.request("my_resource", async (lock) => {
  // ロックを確保した
});

モードの例

以下の例では、リーダーとライターがどのように mode を用いるかを示します。

両方の関数が my_resource というロックを用いることに注意してください。do_read()'shared' モードでロックを要求します。これは、異なるイベントハンドラー・タブ・ワーカーが同時に呼び出せるということです。

js
async function do_read() {
  await navigator.locks.request(
    "my_resource",
    { mode: "shared" },
    async (lock) => {
      // ここで読み込みを行う
    },
  );
}

do_write() 関数は、同じロックを 'exclusive' モードで用います。これは、書き込み操作が完了するまで do_read() 関数内の request() の呼び出しを遅らせます。これはイベントハンドラー・タブ・ワーカーにまたがって適用されます。

js
async function do_write() {
  await navigator.locks.request(
    "my_resource",
    { mode: "exclusive" },
    async (lock) => {
      // ここで書き込みを行う
    },
  );
}

ifAvailable の例

既に確保されていないときのみロックを獲得するには、ifAvailable オプションを用います。この関数では、await によりメソッドをコールバックが完了するまで帰らないようにしています。ロックは利用可能なときのみ獲得できるので、この呼び出しはロックが他のどこかで解放されるのを待たずにすみます。

js
await navigator.locks.request(
  "my_resource",
  { ifAvailable: true },
  async (lock) => {
    if (!lock) {
      // ロックが獲得できなかったので、早期脱出する
      return;
    }

    // ロックが獲得できた。このオリジンで実行中の他のコードは
    // このコードが帰るまで 'my_res_lock' ロックを確保できない。
  },
);

signal の例

短時間のみロックを待機するには、signal オプションを用います。

js
const controller = new AbortController();
// 200ms まで待つ
setTimeout(() => controller.abort(), 200);

try {
  await navigator.locks.request(
    "my_resource",
    { signal: controller.signal },
    async (lock) => {
      // ロックが獲得できた!
    },
  );
} catch (ex) {
  if (ex.name === "AbortError") {
    // ロックの獲得前に要求が中断された
  }
}

仕様書

Specification
Web Locks API
# api-lock-manager-request

ブラウザーの互換性

BCD tables only load in the browser