Web Locks API
(developer.mozilla.org)- Web Locks API は、単一のタブまたは Web Worker で非同期にロックを取得し、処理を行った後にロックを解放できるようにする
- ロックが保持されている間、同一 origin 内の他のスクリプトは同じロックを取得できないため、複数のタブや Worker 間でリソースを安全に調整できる
- Secure Context(HTTPS) でのみ利用可能で、Web Workers でも使用可能
主な概念と使い方
- ロック(Lock) は、Web アプリケーションで定義した名前で識別される抽象的なリソース
- たとえば、複数のタブで IndexedDB とネットワーク同期を行う場合、「my_net_db_sync」というロックを使って、一度に 1 つのタブだけが同期を実行できる
- 利用の流れ:
- ロックを要求
- 非同期処理を実行
- 処理完了後に自動でロックを解放
サンプルコード
navigator.locks.request("my_resource", async (lock) => {
await do_something();
await do_something_else();
});
- ロックが保持されている間、同じロックに対する他のリクエストはキューに追加され、ロックが解放されると最初のリクエストが処理される
オプション
- mode: 既定モードは「exclusive」(排他的)で、「shared」(共有)モードも利用可能。「exclusive」は 1 つの要求のみ許可し、「shared」は複数許可できる
- ifAvailable: すぐにロックを取得できない場合は要求が失敗し、コールバックは null を返す
- steal: 同じ名前の既存ロックを解放し、新しい要求を優先処理する
- signal: AbortSignal を通じて要求を中断できる(例: タイムアウトの実装)
モニタリング
- navigator.locks.query() を使って、現在の origin のロック状態を確認できる
- これはデバッグ時に便利で、どのロックが保持されているか、どのロックが要求されているかを確認できる
高度な使い方
- 非同期処理の完了時点を明示的に制御したい場合は Promise を返せる
let resolve;
const p = new Promise((res) => { resolve = res });
navigator.locks.request("my_resource", (lock) => p);
- resolve() を呼び出すとロックが解放される
デッドロックの防止
- デッドロックとは、異なる要求が順序の問題で衝突し、進行できなくなる状況
- たとえば、タブ 1 がロック A を保持し、タブ 2 がロック B を保持している状況で、タブ 1 がロック B を要求し、タブ 2 がロック A を要求すると、互いに待機することになる
- これを防ぐには:
- ロック要求を入れ子にしない
- ロック要求は順序を守って進める
- タイムアウトを設定して要求を中断する
インターフェース
- Lock: 要求されたロックの名前とモードを提供
- LockManager: 新しいロックを要求したり既存のロックを確認したりできるメソッドを提供
- navigator.locks でインスタンスを取得できる
- WorkerNavigator.locks は Web Workers で利用可能
仕様とブラウザ対応
- 仕様: Web Locks API
- ブラウザ互換性: 一部のブラウザのみ対応しており、最新ブラウザでの対応状況は MDN で確認可能
GN⁺ の意見
- Web Locks API は、非同期環境でのリソース同期の問題を解決するのに有用
- デッドロックが発生する可能性があるため、使用時には注意が必要で、タイムアウト設定のような安全策を検討すべき
- Shared mode は読み取り専用処理で性能を高められるが、それでも競合状態について十分な検討が必要
- この API は、既存の localStorage や IndexedDB の同期問題を解決する代替手段として活用できる
まだコメントはありません。