여러 탭이 같은 출처의 저장소를 갱신하거나 같은 백그라운드 작업을 시작하면 중복 실행과 경쟁 상태가 생길 수 있습니다. Web Locks API는 브라우저 안의 같은 origin 스크립트가 이름 있는 잠금을 요청하도록 해 이런 작업을 조정합니다. 잠금은 탭 사이에서 공유되지만, 서버나 다른 장치와 분산 잠금을 만드는 기능은 아닙니다. 이 API는 지원하는 브라우저의 HTTPS 등 secure context에서 사용할 수 있습니다.

같은 origin의 탭 A가 exclusive 잠금을 callback Promise 완료까지 유지하고, 해제 후 대기 중인 탭 B가 잠금을 받는 흐름

1. 이름과 shared·exclusive 모드

navigator.locks.request(name, callback)은 잠금 이름과 작업 함수를 전달합니다. 기본 요청은 exclusive이므로 같은 이름의 다른 exclusive 요청이 동시에 임계 구역을 실행하지 않도록 조정합니다. 읽기처럼 서로 함께 실행해도 되는 작업은 mode: 'shared'를 요청할 수 있으며, 여러 shared 잠금은 함께 보유될 수 있습니다. 같은 이름의 exclusive 요청은 공유 잠금이 끝날 때까지 기다립니다.

잠금 이름은 애플리케이션이 정하는 논리 식별자입니다. 예를 들어 저장소 동기화와 보고서 생성이 동일한 데이터를 수정한다면 의도에 맞는 이름을 공유할 수 있습니다. 서로 다른 자원에 같은 이름을 우연히 사용하면 불필요한 대기가 생기고, 같은 자원에 다른 이름을 붙이면 조정이 되지 않습니다. 잠금 이름의 규칙을 코드베이스 안에서 일관되게 관리해야 합니다.

2. Callback Promise가 정하는 점유 시간

브라우저는 잠금 요청이 승인되면 callback을 실행합니다. 잠금은 callback이 반환한 Promise가 완료될 때까지 유지되고, 성공·오류 어느 쪽으로 끝나도 해제됩니다. 따라서 callback 안에서 잠금이 필요한 비동기 작업을 기다려야 합니다. 비동기 작업을 시작한 뒤 완료를 기다리지 않고 callback을 반환하면 작업이 잠금 밖에서 계속되어 보호 구간이 끝날 수 있습니다. 반대로 오래 걸리는 네트워크 요청이나 사용자 입력까지 잠금 안에서 기다리면 다른 탭이 오래 대기할 수 있습니다.

3. 같은 출처 경계와 조정 한계

Web Locks는 같은 출처의 브라우저 컨텍스트 사이 자원 사용을 조정합니다. 다른 origin이나 별도 브라우저 프로필, 다른 기기의 프로세스와는 잠금을 공유하지 않습니다. 탭이 닫히거나 worker가 종료되면 해당 실행 컨텍스트의 작업도 끝날 수 있으므로, 잠금만을 영속 작업 큐처럼 사용해서는 안 됩니다. 중요한 결과는 저장소나 서버에 별도로 기록해야 합니다.

이 API는 경쟁 상태를 줄이는 조정 도구이지, 데이터베이스 트랜잭션이나 서버측 중복 방지 키와 동일하지 않습니다. 여러 잠금을 중첩해서 얻으려 하면 요청 순서에 따라 교착 대기나 응답 지연이 생길 수 있습니다. 필요한 자원 이름을 좁히고, callback 시간을 짧게 유지하며, 탭 종료와 브라우저 종료가 발생해도 애플리케이션 상태가 복구되도록 설계합니다.

4. 전문가 관점: 기다리지 않거나 대기를 취소하기

MDN의 request() 전문 안내에 따르면 ifAvailable이 true일 때 즉시 잠금을 받을 수 없으면 callback에 Lock 대신 null이 전달됩니다. callback이 호출됐다는 사실만으로 보호 구간에 들어갔다고 판단해서는 안 됩니다. null을 확인한 분기에서는 보호가 필요한 갱신을 실행하지 않고 이번 작업을 건너뛰거나 다른 결과를 반환할 수 있습니다. 예를 들어 캐시 재생성이 이미 진행 중이라면 두 번째 탭은 새 재생성을 시작하지 않는 정책을 선택할 수 있습니다.

반면 signal에 전달한 AbortSignal은 아직 승인되지 않은 잠금 요청을 대기열에서 취소합니다. MDN은 취소된 요청의 Promise가 거부된다고 설명합니다. 이미 승인되어 실행 중인 callback의 업무 처리를 이 옵션이 자동으로 취소하지는 않습니다. 진행 중인 fetch 등도 중단하려면 그 작업의 취소 인터페이스에 별도로 신호를 연결하고 부분 완료 상태를 처리해야 합니다.

두 옵션은 서로 다른 정책입니다. ifAvailable은 즉시 확보 여부에 따라 null 분기를 실행하고, signal은 기다리는 요청을 취소합니다. MDN은 signal을 지정하면서 ifAvailable을 true로 설정하면 NotSupportedError가 발생한다고 명시하므로 두 방식을 한 요청에 겹치지 않습니다. 다중 탭 테스트에서 잠금을 보유한 탭을 만든 뒤 null 분기, 대기 요청 취소, 승인 후 신호 취소를 각각 확인하면 callback이 시작된 시점과 취소의 경계를 구분할 수 있습니다.

출처