Files
2nd/10_Wiki/Topics/Coding/Web_Web_Locks_API.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

7.0 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
web-web-locks-api Web Locks API — tab 간 mutex Coding draft B conceptual 2026-05-09 2026-05-09
web
lock
vibe-coding
language applicable_to
TS
Frontend
Web Locks
navigator.locks
tab synchronization
broadcast channel
mutex
exclusive lock

Web Locks API

같은 origin 의 여러 tab 가 race condition. navigator.locks 가 mutex. Sync between tabs / workers. Modern browsers.

📖 핵심 개념

  • 같은 origin 의 다른 tab / worker / iframe 사이.
  • Exclusive (1) 또는 shared (read).
  • 매 lock 가 자동 release (tab close).
  • BroadcastChannel 와 함께 사용.

💻 코드 패턴

Exclusive lock

await navigator.locks.request('my-resource', async (lock) => {
  // 매 origin 에서 1 곳 만.
  await criticalSection();
});
// → Lock 자동 release.

Shared lock (read)

await navigator.locks.request('config', { mode: 'shared' }, async (lock) => {
  // 여러 tab 가 동시 read.
});

await navigator.locks.request('config', { mode: 'exclusive' }, async (lock) => {
  // Write — shared 가 wait.
});

→ Reader / writer.

Use case: leader election

// 1 tab 만 가 background work
let isLeader = false;

navigator.locks.request('leader', { mode: 'exclusive' }, async () => {
  isLeader = true;
  while (isLeader) {
    await pollServer();
    await new Promise(r => setTimeout(r, 5000));
  }
});

window.addEventListener('beforeunload', () => {
  isLeader = false;
});

→ 새 tab 가 lock = leader.

→ "Service Worker 가 leader" 의 alternative.

TryLock (안 wait)

const result = await navigator.locks.request('resource', { ifAvailable: true }, async (lock) => {
  if (!lock) return 'busy';
  // ...
  return 'done';
});

ifAvailable: true = 잠겼으면 lock=null + callback 즉시.

Timeout (own logic)

async function lockWithTimeout(name: string, ms: number, fn: () => Promise<void>) {
  const ac = new AbortController();
  setTimeout(() => ac.abort(), ms);
  
  await navigator.locks.request(name, { signal: ac.signal }, fn);
}

→ N ms 안 lock 못 = AbortError.

Query state

const { held, pending } = await navigator.locks.query();
console.log('Held locks:', held.map(l => l.name));
console.log('Pending:', pending.map(l => l.name));

→ Debug.

vs SharedWorker

SharedWorker: 같은 origin tab 가 공유 worker.
Web Locks: 작은 mutex.

→ 둘 다 사용 가능.
SharedWorker = 큰 logic 공유.
Web Locks = small lock.

vs BroadcastChannel

BroadcastChannel: tab 간 message.
Web Locks: tab 간 lock.

→ 함께 사용 흔함.
const channel = new BroadcastChannel('updates');
channel.postMessage({ type: 'config-changed' });

// Other tab
channel.onmessage = (e) => {
  if (e.data.type === 'config-changed') {
    reloadConfig();
  }
};

Use case: IndexedDB write coordinate

// 여러 tab 가 같은 data 변경 → conflict.
async function updateConfig(newValue) {
  await navigator.locks.request('config-write', async () => {
    const tx = db.transaction('config', 'readwrite');
    await tx.objectStore('config').put(newValue);
  });
}

Service Worker + Web Locks

// Service worker
self.addEventListener('fetch', async (event) => {
  await navigator.locks.request('cache-write', async () => {
    const cache = await caches.open('v1');
    cache.put(event.request, response);
  });
});

→ Cache 가 tab 간 + worker 사이 안전.

함정

- Tab 간 만 (cross-origin X).
- Worker 도 같은 origin.
- Indexed DB transaction 가 별도 lock (혼동 X).

Browser support

Chrome 69+, Edge 79+, FF 96+, Safari 15.4+.
→ 모든 modern.

Polyfill 가 어려움

Cross-tab lock 가 native 만 신뢰.
Polyfill = localStorage 로 가능 (race condition 위험).

Use case 모음

1. Leader election (single tab background work).
2. IndexedDB write serialize.
3. Cache 정리 (1 tab 만).
4. WebSocket 1 connection share.
5. Background sync coordinate.

Single WebSocket pattern

async function connectIfLeader() {
  await navigator.locks.request('ws-connection', async () => {
    const ws = new WebSocket('wss://...');
    // ws → BroadcastChannel 가 다른 tab 에 전달
    ws.onmessage = (e) => {
      bc.postMessage({ type: 'message', data: e.data });
    };
    
    // Hold lock — tab close = release
    await new Promise(() => {});
  });
}

→ 1 WS, N tab 공유.

Lock 의 ordering

First-come, first-served (queue).
- Tab A request → wait.
- Tab B request → wait B.
- Tab C request → wait C.
- A 끝 → B 시작 → 등.

Re-entrancy 안 됨

await navigator.locks.request('x', async () => {
  // ❌ 재 lock — deadlock.
  await navigator.locks.request('x', async () => {});
});

→ Promise pending forever.

일반 mutex 와 차이

일반 mutex: 같은 process.
Web Locks: cross-tab (다른 process).

→ Browser 가 origin-scoped lock manager.

Auto-release

Tab close, navigation, crash:
→ Lock 자동 release.

⚠️ 매 lock 가 finite life — 무한 hang X.

Production tip

- Lock 안 work 가 빠름 (다른 tab block).
- Long-running = SharedWorker 가 더 좋음.
- Critical path 만 lock.
- Debug 로 query() 활용.

LiveBlocks / PartyKit (alternative)

Cross-tab sync = Web Locks 의 idea + cross-device.

→ Different problem (tab 가 아닌 user).

함정: Worker 안 사용

// Worker 안
self.onmessage = async (e) => {
  await navigator.locks.request('x', async () => {
    // OK — worker 도 same-origin lock 참여
  });
};

Same-site / origin / Tab 이해

example.com / about.html / 가 lock 공유.
example.com / sub.html / 도 공유.
sub.example.com 는 안 (다른 origin).

Storage event (옛 방법)

// localStorage 변경 = 다른 tab 가 'storage' event.
// → Pseudo-lock (race condition 위험).

window.addEventListener('storage', (e) => {
  if (e.key === 'lock-X' && e.newValue === 'taken') {
    // ...
  }
});

→ Web Locks 가 modern + 안전.

🤔 의사결정 기준

작업 추천
Tab 간 mutex Web Locks
1 tab 만 background Leader election
Tab 간 message BroadcastChannel
Logic 공유 SharedWorker
Try lock ifAvailable: true
Timeout AbortController + signal
Read/write shared / exclusive mode

안티패턴

  • localStorage 로 fake lock: race.
  • Cross-origin lock 가정: 안 됨.
  • Re-entrant lock: deadlock.
  • Long work in lock: 다른 tab freeze.
  • Auto-release 무시: leak 가정.
  • Web Locks 만 + sync 없음: BroadcastChannel 함께.

🤖 LLM 활용 힌트

  • Web Locks 가 cross-tab mutex 의 답.
  • Leader election + BroadcastChannel 가 SharedWorker 의 작은 alternative.
  • Auto-release 가 큰 강점.
  • Browser support 가 좋음 (modern).

🔗 관련 문서