前端 Web Locks 怎样查询当前持有者
多个标签页同时同步数据时,最难排查的往往不是“有没有调用 navigator.locks.request()”,而是当前到底谁拿到了锁、哪些请求还在排队。Web Locks 提供了 navigator.locks.query(),它返回当前 origin 的诊断快照:held 是已持有的锁,pending 是等待中的请求。它只读状态,不会抢锁、释放锁或取消等待。
官方地址:https://developer.mozilla.org/en-US/docs/Web/API/LockManager/query
排查“同步任务卡住”时,先看held里对应的name、mode和clientId;再看pending是否有同名请求。不要把 pending 中的上下文当成当前持有者。
先确认触发信号与查询边界
如果页面表现为重复同步、某个任务迟迟没有进入回调,或者多个标签页像是在互相等待,可以先把问题收窄到“锁状态快照”。Web Locks 按 origin 隔离,来自不同协议、域名或端口的页面不会共享同一个锁管理器。
查询依赖安全上下文,并且页面需要能够取得 navigator.locks。因此排障记录里要同时写下页面 origin、是否 HTTPS、运行环境是标签页还是 Worker。下面的代码只做能力判断,不会创建锁:
function canInspectLocks() {
// Web Locks 需要安全上下文,先避免在不支持的环境中直接访问。
return window.isSecureContext && "locks" in navigator;
}
if (!canInspectLocks()) {
console.warn("当前环境无法读取 Web Locks 状态");
}
这里的“无法读取”可能来自不安全上下文,也可能来自浏览器或运行环境没有实现 API。它不是业务锁被占用的证据。
读取 held 与 pending 两组锁信息
query() 不接收参数,返回一个 Promise。快照中的每个锁记录通常包含三个对排障最有用的字段:name 是请求时的锁名,mode 是 exclusive 或 shared,clientId 是发起请求的执行上下文标识。

async function printLockSnapshot() {
// query() 只读当前 origin 的锁管理器快照,不会修改锁状态。
const snapshot = await navigator.locks.query();
// held 是当前已经授予的锁;同名 shared 锁可能同时出现多个记录。
for (const lock of snapshot.held) {
console.log("held", {
name: lock.name,
mode: lock.mode,
clientId: lock.clientId
});
}
// pending 是尚未授予的请求,不能当作当前持有者。
for (const request of snapshot.pending) {
console.log("pending", {
name: request.name,
mode: request.mode,
clientId: request.clientId
});
}
return snapshot;
}
为了让值班记录可读,可以把输出按“持有区”和“等待区”分开保存。没有任何锁时,两个数组都可能为空;这只能说明查询时刻没有可见的持有或等待记录,不代表稍后不会有新请求。
根据 clientId 判断当前持有者
判断“谁持有锁”时,先在 held 中按 name 过滤,再记录同一条记录的 mode 与 clientId。pending 只说明有请求排队,它的 clientId 可以帮助定位等待方,但不能证明该上下文已经执行了临界区代码。

function summarizeLock(snapshot, targetName) {
// 只从 held 中寻找真正已授予的目标锁,避免把等待请求算成持有者。
const holders = snapshot.held
.filter((lock) => lock.name === targetName)
.map((lock) => ({
mode: lock.mode,
clientId: lock.clientId
}));
// pending 用于解释“为什么还有请求没进去”,单独保留等待上下文。
const waiters = snapshot.pending
.filter((lock) => lock.name === targetName)
.map((lock) => ({
mode: lock.mode,
clientId: lock.clientId
}));
return { targetName, holders, waiters };
}
这里的 clientId 是浏览器为执行上下文提供的标识,不应直接当作用户 ID、标签页标题或业务会话名。若需要把它映射到业务日志,应在应用自己的请求上下文中另行记录,不要猜测 Web Locks 字段的含义。
处理查询失败、空快照与回滚路径
查询本身可能返回拒绝的 Promise。官方接口列出的常见异常包括文档尚未 fully active 时的 InvalidStateError,以及无法取得锁管理器时的 SecurityError。运行手册中应把这些情况和“锁确实被别的标签页持有”分开。
async function inspectLocksSafely() {
try {
// 只在能力检查通过后调用 query(),将异常转成可追踪的诊断结果。
const snapshot = await navigator.locks.query();
return {
ok: true,
held: snapshot.held,
pending: snapshot.pending
};
} catch (error) {
// 保留异常类型,便于区分上下文问题与业务锁等待。
return {
ok: false,
errorName: error.name,
message: error.message
};
}
}
如果结果是空快照,复盘时记录查询时间和 origin;如果结果是异常,记录 errorName 和页面生命周期状态。回滚路径也很明确:查询函数只撤回诊断日志,不对现有锁做强制操作;真正的锁释放仍由持锁请求的异步回调结束来完成。
告警确认与复盘项
线上告警可以把“同名锁持续出现在 held”“pending 数量持续增长”“query() 连续失败”作为不同信号,但不要只凭一次快照下结论。对每次采样保存 name、mode、clientId、origin 和采样时间,之后再和同步任务日志关联。
复盘时重点问三件事:锁名是否过于宽泛,导致无关任务排队;持锁回调是否包含了不必要的慢操作;等待方是否有超时或用户可见的降级路径。query() 能告诉你“当前看见了什么”,但不能替应用决定锁应该由谁释放。
常见问题
query() 能直接查某一个锁名吗?
不能。query() 没有参数,会返回快照;需要查询某个名字时,在返回的 held 和 pending 数组上用 name 过滤。
pending 里的 clientId 是当前持有者吗?
不是。它代表发起等待请求的执行上下文。当前持有者应从同名锁的 held 记录中判断。
调用 query() 会让等待请求立即获得锁吗?
不会。它是诊断查询,不改变授予、排队或释放状态。
把 held 当作当前授予结果,把 pending 当作等待记录,再用 clientId 关联执行上下文,就能把“谁在持锁”从猜测变成可复查的状态快照。
前端 Intl.Segmenter 怎样按语言边界切分文本
- 上一篇
- 前端 Intl.Segmenter 怎样按语言边界切分文本
- 下一篇
- 农业经营者怎样留存农产品批次追溯记录
-
- 文章 · 前端 | 1小时前 | 前端 · javascript · JavaScript 国际化 语言边界 Intl.Segmenter 文本分词
- 前端 Intl.Segmenter 怎样按语言边界切分文本
- 432浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · 泛型 · typescript · TypeScript 泛型 keyof 对象键 属性读取
- TypeScript keyof 怎样约束对象键并安全读取属性
- 432浏览 收藏
-
- 文章 · 前端 | 1小时前 | ArrayBuffer structuredClone transfer
- 前端 structuredClone 怎样处理嵌套可转移对象
- 464浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · css · 深色模式 color-scheme light-dark CSS主题
- CSS light-dark 怎样为浅色深色主题切换颜色
- 379浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · css · CSS 组件布局 容器查询 container-type @container container-name
- CSS container-type 怎样隔离组件查询范围
- 295浏览 收藏
-
- 文章 · 前端 | 1小时前 |
- 前端 PerformanceObserver 怎样接收长任务条目
- 182浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端性能 PerformanceResourceTiming 资源响应时间
- 前端 PerformanceResourceTiming 怎样定位资源响应时间
- 150浏览 收藏
-
- 文章 · 前端 | 1小时前 |
- 前端 addEventListener 怎样用 once 自动移除一次性监听
- 204浏览 收藏
-
- 文章 · 前端 | 1小时前 |
- 前端 ResizeObserver 怎样读取内容盒和边框盒尺寸
- 114浏览 收藏
-
- 文章 · 前端 | 1小时前 | 状态同步 BroadcastChannel 跨标签页
- 前端 BroadcastChannel 怎样同步不同标签页状态
- 306浏览 收藏
-
- 文章 · 前端 | 1小时前 | 前端 · javascript · 浏览器API · JavaScript 命名参数 前端路由 URLPattern pathname
- 前端 URLPattern 怎样按命名参数匹配路由路径
- 184浏览 收藏
-
- 文章 · 前端 | 1天前 | typescript ·
- TypeScript 怎样让索引访问显式处理 undefined
- 404浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 553次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 604次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 631次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 586次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 410次使用
-
- Go并发控制Channel使用场景分析
- 2022-12-23 459浏览
-
- Go并发控制WaitGroup的使用场景分析
- 2023-02-16 264浏览
-
- Golang 语言控制并发 Goroutine的方法
- 2023-01-07 285浏览
-
- Golang 实现分片读取http超大文件流和并发控制
- 2022-12-24 140浏览
-
- Go 并发控制context实现原理剖析(小结)
- 2023-01-01 470浏览

