跳转到内容

能力 · API

Web Locks API

发布于 更新于

自 2022-03 起广泛可用W3C 草案

navigator.locks.request() 向浏览器的锁管理器申请一把命名锁,在持锁期间运行回调,回调的 Promise 完结后释放。同一源下共享同一个存储桶的标签页、iframe 和 worker 在相同名字上排队,因此 PWA 可以把对 IndexedDB 的写入串行化、选出一个标签页独占 WebSocket,或防止两个 Service Worker 客户端同时跑同一份迁移。

支持面很宽:Chrome 69、Edge 79、Firefox 96、macOS 与 iOS 上的 Safari 15.4、Samsung Internet 10.0 以及 Android WebView 69 都实现了带 request() 与 query() 的 LockManager(BCD api.LockManager)。接口标注为 [SecureContext, Exposed=(Window,Worker)],所以在专用、共享与 Service Worker 中都可用,但在 localhost 以外的 http:// 源上不存在。

navigator.locks.request(name, callback)
navigator.locks.request(name, options, callback)
navigator.locks.query()

request() 返回 Promise<any>,在锁释放之后以 callback 的返回值兑现或以其抛出的值拒绝。同步回调会被包成一个立即兑现的 Promise,所以锁只在同步执行期间被持有。query() 返回 Promise<LockManagerSnapshot>,描述快照那一刻该源锁管理器里每一把已持有和排队中的锁。

request() 接受资源名、可选的 LockOptions 字典和一个回调;回调始终是最后一个参数。

参数 类型 必填 说明
name DOMString 是 由应用自行命名的资源名。以 - 开头的名字保留给浏览器,会被拒绝。
options LockOptions 否 模式与等待行为,见下表。
callback LockGrantedCallback 是 (lock) => Promise<any> | any,授予时以 Lock(name、mode)调用;ifAvailable 为 true 且无法立即授予时以 null 调用。

LockOptions 有四个成员,全部可选。

成员 类型 默认值 说明
mode LockMode("exclusive" 或 "shared") "exclusive" 多个上下文可同时持有同名的 "shared" 锁;"exclusive" 持有者会阻塞该名字上的所有其他请求直到释放。
ifAvailable boolean false 只在无需等待时授予,否则以 null 调用 callback 而不排队。仍是异步的,因为检查通常要跨进程。
steal boolean false 释放该名字的当前持有者(它们的 request() Promise 以 AbortError 拒绝),跳过队列并授予本次请求。只能与 "exclusive" 模式搭配。
signal AbortSignal 无 在请求仍在排队时中止它;锁一旦授予,信号即被忽略。

query() 不接受参数。其快照包含 held 与 pending 两个 LockInfo 数组,每项带 name、mode 以及所在 frame 或 worker 的 clientId(与 Service Worker 里 Client.id 的值相同)。

出现下列情况之一时,request() 在任何锁入队之前即拒绝,顺序与规范的方法步骤一致。

异常 条件
InvalidStateError 调用方文档不是 fully active(例如已脱离文档树的 iframe)。
SecurityError 无法为该环境获取锁管理器:不透明源(如没有 allow-same-origin 的沙箱 iframe),或浏览器排除在 Locks API 之外的上下文。
NotSupportedError name 以 U+002D HYPHEN-MINUS(-)开头;steal 与 ifAvailable 同为 true;steal 为 true 但 mode 不是 "exclusive";或同时传了 signal 与 steal 或 ifAvailable。
AbortError(或信号的 abort reason) 调用 request() 时 signal 已经中止,或请求仍在排队时被中止。
AbortError 另一个带 steal: true 的请求夺走了本持有者的锁。

query() 只会以同样的 InvalidStateError 与 SecurityError 条件拒绝。两个方法都不同步抛出;回调抛出的任何值都会在锁释放后成为 request() Promise 的拒绝原因。

每个示例都先检测 navigator.locks,并给出缺失时执行的分支;在上文列出的浏览器里,回退分支只会在非安全源上运行。

打开同一个数据库的两个标签页可能同时判断需要升级 schema。把升级包进一把独占锁,第二个标签页就会先等待,然后发现活已经干完。没有锁支持时函数直接执行升级,这也正是引入锁之前代码的行为。

async function withLock(name, work) {
if (!('locks' in navigator)) return work();
return navigator.locks.request(name, work);
}
await withLock('db-migration', async () => {
const version = await readSchemaVersion();
if (version < 3) await migrateTo3();
});

回调的返回值会成为外层 Promise 的值,所以 withLock() 可以把持锁期间读到的数据直接返回,不必再跑一个来回。

排在一个卡在长回调里的标签页后面的请求,否则会一直等下去。传入 AbortSignal 并由定时器中止它;拒绝原因就是传给 abort() 的值,没传时为 AbortError。

async function requestWithTimeout(name, ms, work) {
if (!('locks' in navigator)) return work();
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(new DOMException('Lock wait exceeded', 'TimeoutError')), ms);
try {
return await navigator.locks.request(name, { signal: controller.signal }, work);
} catch (err) {
if (err.name === 'TimeoutError') return null;
throw err;
} finally {
clearTimeout(timer);
}
}

锁一旦授予,信号就被忽略,之后再中止也不会打断 work()。

让读者共享缓存、由一个写者刷新

Section titled “让读者共享缓存、由一个写者刷新”

共享锁允许任意数量的读者同时进行,而写者要等它们全部结束,然后阻塞新的读者。ifAvailable: true 让刷新步骤在已有写者持锁时直接跳过,而不是排队再做一次重复刷新。

async function readCatalog() {
if (!('locks' in navigator)) return loadCatalogFromCache();
return navigator.locks.request('catalog', { mode: 'shared' }, () => loadCatalogFromCache());
}
async function refreshCatalog() {
if (!('locks' in navigator)) return fetchAndStoreCatalog();
return navigator.locks.request('catalog', { ifAvailable: true }, async (lock) => {
if (!lock) return 'skipped';
await fetchAndStoreCatalog();
return 'refreshed';
});
}

刷新总是返回 'skipped' 时,navigator.locks.query() 能显示是哪个 clientId 以什么模式持有 catalog。

规范

规范状态
Web Locks API(网页锁)W3C 草案
Web Locks API: request() methodW3C 草案
Web Locks API: query() methodW3C 草案
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Desktop)支持69高来源—
Chrome (Android)支持69高来源1
Edge (Desktop)支持79高来源2
Firefox (Desktop)支持96高来源—
Firefox (Android)支持96高来源3
Safari (macOS)支持15.4高来源—
Safari (iOS)支持15.4高来源4
Samsung Internet支持10.0高来源5
WebView (Android)支持69高来源6
  1. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  2. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  3. 由 browser-compat-data 镜像自 Firefox 的数据推导。
  4. 由 browser-compat-data 镜像自 Safari 的数据推导。
  5. 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
  6. 由 browser-compat-data 镜像自 Chrome Android 的数据推导。

源数据: /compatibility/web-locks.json · 全球使用占比: 93 % (StatCounter 2026-05)

来源: 规范 · MDN · 最近核验 2026-10-03 · 置信度: 高 (由来源计算)