Web Locks API不能实现真正的主从选举,仅支持同源多标签页间短时互斥抢占;成功获取'leader-lock'的标签页视为临时主节点,但无故障感知、超时续约或跨设备能力,需配合visibility和beforeunload事件提升稳定性。

Web Locks API 本身不支持跨标签页的“主从选举”或长期状态维持,它只提供轻量级、短时、浏览器进程内互斥锁,无法替代分布式系统中的 Leader 选举算法(如 Raft、ZAB)或协调服务(如 etcd、ZooKeeper)。但你可以用它在**同一浏览器实例的多个标签页间实现简易的“单主抢占”逻辑**,适用于前端场景下的 UI 控制权协商,比如:仅一个标签页播放音频、同步刷新 token、防止重复提交等。
核心限制必须清楚
Web Locks API 的设计目标不是做高可用协调,而是解决页面内资源争用。它的关键约束包括:
- 锁作用域限于同一源(origin)+ 同一 browsing context group(通常是同一个浏览器窗口/进程内的所有标签页),无法跨浏览器或跨设备
- 锁不具备持久性:页面关闭、标签页崩溃、Service Worker 未激活时锁自动释放,无故障通知机制
- 无内置心跳、超时续约、节点发现或广播能力,不能感知其他标签页是否“存活”,只能靠尝试获取锁来间接判断
- 不保证公平性或顺序性,竞争结果取决于浏览器调度,可能造成某标签页长期抢不到锁
简易“主节点”抢占式选举逻辑
利用 navigator.locks.request() 的排他性和异步特性,可模拟一轮无状态的“竞选”:
- 每个标签页启动时,调用
navigator.locks.request('leader-lock', callback) - 成功进入 callback 的标签页即视为“当选主节点”,可执行业务逻辑(如开启定时器、接管 WebSocket 连接)
- 未获得锁的标签页保持“从节点”状态,监听自身是否被后续释放的锁唤醒(通过再次 request 或轮询)
- 主节点需主动释放锁(
navigator.locks.release('leader-lock'))或依赖页面卸载自动释放
注意:这不是持续选举,而是一次性抢占;若主节点异常退出,其他标签页需重新发起 request 才有机会接任——中间存在空窗期。
配合 Page Visibility 和 beforeunload 做基本状态维持
单纯靠锁不够稳定,需叠加浏览器原生事件提升鲁棒性:
- 监听
document.visibilityState:当主节点标签页切到后台(visibilityState === 'hidden'),可主动 release 锁,让前台标签页快速接替 - 监听
beforeunload:在页面关闭前释放锁,避免锁残留(虽然浏览器通常会自动清理,但显式释放更可靠) - 用
localStorage+storage事件辅助传递轻量状态:例如主节点写入localStorage.setItem('leader-id', Date.now()),其他标签页监听 change 并比对时间戳,辅助判断谁是最新当选者(仅作参考,不具强一致性)
不适合什么场景
以下需求 Web Locks API 无法满足,应转向后端协调服务:
- 需要跨浏览器、跨设备统一视图(如用户在 Chrome 和 Safari 同时打开,只能有一个主)
- 要求严格故障转移(主挂了必须毫秒级切换,且不丢任务)
- 涉及分布式事务、数据写入一致性、多节点协同状态机
- 需记录选举历史、任期编号、日志复制等 Raft/ZAB 级语义
这类场景必须由 etcd(Raft)、ZooKeeper(ZAB)或 Nacos 等后端协调组件完成,前端只作为 follower 订阅 leader 变更事件。

















