Web Locks API是浏览器原生轻量级并发协调机制,用于解决同源多标签页/Worker对共享资源的竞态问题;需锁名精准(如user-cart-${userId})、模式明确(写操作用{mode:'exclusive',ifAvailable:true})、范围最小(锁内仅执行“读–改–写”核心逻辑)、释放可靠(await tx.done);Safari不支持,服务端幂等为兜底。

Web Locks API 是浏览器原生提供的轻量级并发协调机制,专为解决同源多标签页、Worker 等上下文对共享资源(如 IndexedDB、localStorage、内存状态)的竞态问题而设计。它不替代服务端幂等,但能显著提升前端本地操作的原子性与一致性——关键在于“锁名精准”、“模式明确”、“范围最小”、“释放可靠”。
锁名必须带业务粒度标识,避免全局误阻塞
用固定字符串如 'cart' 或 'draft' 作锁名,会导致所有用户、所有文档共用一把锁。实际应绑定具体业务实体 ID:
- 用户购物车:用
`user-cart-${userId}`,而非'cart' - 文档草稿:用
`draft-${docId}`,确保 A 编辑 doc-101 时,B 编辑 doc-202 不受影响 - 锁名需 URL-safe:避免空格、斜杠、控制字符;长度建议 ≤64 字符,过长可能影响内部哈希性能
写操作必须用 exclusive 模式 + ifAvailable:true 防卡死
默认 mode 是 'exclusive',但旧版 Chrome 曾静默 fallback 到 'shared',导致看似加锁实则无效。务必显式声明:
- 写入 IndexedDB 或 localStorage 时,始终传
{ mode: 'exclusive', ifAvailable: true } -
ifAvailable: true表示锁不可用时立即返回null,而非无限等待——UI 不会卡住,可转为提示或降级策略 - 若需等待,改用
signal配合AbortController设置超时,例如 3 秒未获锁则放弃
只包“读–改–写”核心逻辑,副作用全部移出锁外
锁持有时间越长,其他标签页排队越久。锁内只做真正需要互斥的部分:
- ✅ 正确:打开数据库 → 启动事务 → 读取旧值 → 计算新值 → 写入 → await tx.done
- ❌ 错误:在锁内发起 fetch 请求、执行大数组排序、更新 DOM、打日志、触发通知
- 特别注意:
tx.commit()不保证写入落地,必须await tx.done,否则锁提前释放,其他标签页可能读到中间态
Safari 不支持是事实,服务端幂等才是兜底底线
iOS 17.5 / macOS 14.5 的 Safari 仍未实现 Web Locks API。仅靠 if ('locks' in navigator) 跳过逻辑,等于在 Safari 中完全放弃保护:
- 服务端必须校验客户端生成的
requestId,拒绝重复请求(幂等 key 由前端生成并随请求携带) - 前端可轻量 fallback:用
localStorage.setItem('lock:cart-123', Date.now())+storage事件监听冲突,仅作友好提示(非强一致) - 私有模式、跨设备、不同源标签页天然不共享锁,这些场景本就不在 Web Locks 作用范围内

















