3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🔒 Web Locks API をもっとシンプルに扱う ― disposable-lock を公開しました

Last updated at Posted at 2025-11-14

ブラウザが提供する Web Locks API は、タブ間や非同期処理間でリソースの競合を避ける便利な仕組みですが、
コールバックベースで扱いづらい という課題があります。

そこで、Web Locks API をより現代的に使えるようにした軽量な TypeScript ライブラリ
disposable-lock を公開しました。


🚀 disposable-lock とは?

Web Locks API をシンプルに扱うための、依存ゼロの TypeScript ライブラリ
Promise ベース & await using による自動解放に対応

  • 🧩 依存なし・Pure TypeScript
  • 🔁 Promise ベースのロック取得 / 解放
  • 🪄 await using 対応Symbol.asyncDispose
  • 🧠 custom LockManager を注入可能(Node.js / テストで便利)

📦 インストール

npm install disposable-lock
# or
pnpm add disposable-lock

✋ まずは基本の使い方

import { lock } from "disposable-lock";

async function main() {
  const { request } = lock("user-data");

  const acquired = await request({ mode: "exclusive" });

  if (acquired.name) {
    console.log(`Lock acquired: ${acquired.name}`);

    await doSomethingCritical();

    await acquired.release();
  } else {
    console.log("Lock not available.");
  }
}

Web Locks API の複雑なコールバックを隠蔽し、
「ロックを取得 → 作業 → release」
という流れを直感的に書けます。

🪄 await using で自動解放

Node.js 20+ / 最新ブラウザなら、Symbol.asyncDispose を使えます。

(※ Safari はまだ対応していないので tsconfig で target:es2022 等で 変換されるように調整が必要です

import { lock } from "disposable-lock";

async function cacheUpdate() {
  const cacheLock = lock("cache");

  // スコープ終了時に自動解放される
  await using acquired = await cacheLock.request();

  await updateCache();
}

release() の書き忘れがなくなり、安全なロック管理ができます。

🔍 Lock の状態を調べたい

const userLock = lock("user-data");
const state = await userLock.query();

console.log("Held:", state.held);
console.log("Pending:", state.pending);

Web Locks API の内部状態が確認しづらい問題を、
query() でシンプルに解決できます。

🧪 テスト環境(Node.js)で LockManager を差し替える

navigator.locks が無い環境でも動かせます。

import { lock } from "disposable-lock";
import { createMockLockManager } from "./mock";

const locks = createMockLockManager();
const fileLock = lock("file-access", { locks });

await using acquired = await fileLock.request();
// テストが書きやすい!

テストしやすいように LockManager の DI を前提として設計しています。

🎯 なぜ作ったのか?

Web Locks API は強力ですが…

  • コールバック構造が複雑
  • dispose(スコープ終了処理)と相性が悪い
  • ロック解放忘れが起きやすい
  • テストしづらい

といった弱点があります。

disposable-lock はこれらを解消し、
「現代的な JS/TS で快適に使える Lock API」 を目指して作りました。

📚 リポジトリ・パッケージ

📝 まとめ

disposable-lock

  • Web Locks API を驚くほど使いやすく
  • TypeScript で型安全
  • await using で確実にロック解放
  • Node.js でもテストでも問題なく動作

という、小さいけれど実用的なロック管理ライブラリです。

ブラウザで排他制御を使う方、
タブ間競合を避けたい方、
テスト可能なロック API がほしい方にぴったりです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?