navigator.locks.query()返回promise,解析为{held: [{name, mode, clientid}], pending: [{name, mode, clientid, starttime}]},仅在安全上下文且用户手势触发时有效。

navigator.locks.query 返回什么结构
navigator.locks.query() 返回一个 Promise,解析为包含两个数组的对象:held(当前持有锁的列表)和 pending(正在等待获取锁的请求列表)。它不返回锁的内容或持有者身份,只反映浏览器内部锁管理器的快照。
注意:该 API 仅在安全上下文(https:// 或 localhost)中可用,且需用户交互触发(如点击事件中调用),否则可能被拒绝或返回空结果。
-
held中每个项是{ name: string, mode: 'exclusive' | 'shared', clientId: string },clientId是当前持有锁的ServiceWorker或页面的唯一标识(不是可读 ID,无法映射到具体标签页) -
pending中每个项是{ name: string, mode: 'exclusive' | 'shared', clientId: string, startTime: number },startTime是调用navigator.locks.request()的时间戳(毫秒) - 锁名(
name)区分大小写,且无命名空间隔离——不同脚本用相同名字会互相竞争
实际调用 query() 的正确时机和方式
不能在页面加载后立即无条件调用 navigator.locks.query(),它会被静默拒绝或返回空对象。必须确保调用发生在用户手势之后(例如按钮点击、键盘事件),且浏览器已启用 Lock Manager API。
示例(带错误防护):
async function inspectLocks() {
try {
const { held, pending } = await navigator.locks.query();
console.log('Held:', held);
console.log('Pending:', pending);
} catch (err) {
// 常见错误:SecurityError(非安全上下文)、NotSupportedError(API 不可用)、InvalidStateError(未在用户手势中)
console.warn('Lock query failed:', err.name, err.message);
}
}
document.getElementById('debug-btn').addEventListener('click', inspectLocks);
- 务必用
try/catch包裹,因为失败不抛出标准TypeError,而是特定DOMException子类 - 不要在
setTimeout或fetch回调中直接调用——这些不属于用户激活状态(user activation) - Chrome 117+ 和 Firefox 120+ 支持,Safari 尚未实现;可通过
'locks' in navigator检测基础可用性
query() 结果里 clientId 怎么理解
clientId 是浏览器分配的 opaque 字符串,形如 "1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p",它对应当前持有或请求锁的 Client(即一个页面、iframe 或 Service Worker 实例),但无法反查该 client 的 URL、title 或是否还在运行。
- 同一个页面刷新后,
clientId必然改变;关闭标签页后,其持有的锁会自动释放,对应项从held消失 - 多个 iframe 若同源且使用相同锁名,它们的请求会排队——
pending列表中能看到各自clientId,但无法判断哪个 iframe 是哪个 - Service Worker 中获取的
clientId与主页面不同,且 SW 可能长期驻留,导致锁“看似”一直被持有(实际是合法行为)
为什么 query() 查不到你刚 request() 的锁
常见错觉:调用 navigator.locks.request('my-lock', cb) 后立刻 query(),却发现 held 为空。这不是 bug,而是因为 request() 是异步的,锁真正被授予前,query() 快照已生成。
- 锁授予发生在
request()的回调执行时(或 Promise resolve 后),而非调用瞬间 - 若想确认某锁是否已持有时,应在
request()的成功回调内再查一次query(),或改用ifAvailable选项避免阻塞 - 没有 API 能“等待锁状态变更”,
query()纯属采样——两次调用间隔哪怕 1ms,结果都可能不同
真正难调试的是锁生命周期和跨上下文竞争,而不是 query() 本身;拿到 clientId 却不知道它属于哪个调试器标签页,这才是最常卡住的地方。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











