web locks需与indexeddb配合实现多窗口并发写入保护:锁须包裹完整读–改–写流程,按业务实体命名锁名,显式设exclusive模式并处理兼容性兜底。

Web Locks 本身不提供数据写入能力,它只负责协调多个窗口谁能在同一时间执行某段代码。要实现真正可靠的多窗口并发写入保护,必须把它和 IndexedDB 配合使用——锁只管“串行化执行”,数据库事务才管“原子性写入”。
锁必须包裹完整读–改–写流程
不能只锁 put() 这一行,否则其他窗口可能在事务还没落地时就拿到锁、读到旧值,导致覆盖。整个链条必须包进去:
- 调用
indexedDB.open()打开数据库 - 启动
readwrite事务 - 用
get()读取当前数据 - 计算新值(尽量轻量,避免耗时逻辑)
- 调用
put()写入 -
必须 await
tx.done(v3+ IndexedDB)或手动等待oncomplete,否则锁提前释放
锁名设计决定是否真有效
锁名不是随便起的标签,而是作用域开关。名字一样才互斥,名字不同等于没锁:
- 避免全局锁如
'idb-write',会把用户头像更新和笔记保存卡在一起 - 推荐按业务实体命名:
'note-123'、'cart-user456' - 对用户输入生成的 ID,建议先
encodeURIComponent()清理,确保 URL-safe - 长度控制在 64 字符内,过长无意义且影响内部哈希性能
必须显式配置 exclusive 模式并启用 ifAvailable
不设 mode: 'exclusive',默认可能 fallback 到 shared,而 shared 锁完全无法阻止并发写入:
- 写操作一律用
{ mode: 'exclusive' } - 高交互场景加
ifAvailable: true,锁不可用时主动降级(比如提示“其他窗口正在编辑”),而不是让用户干等 - 回调必须返回 Promise;同步返回(如
return 'ok')会导致锁瞬间释放
兼容性兜底不能跳过
Safari(截至 iOS 17.5 / macOS 14.5)仍不支持 Web Locks,仅靠 "locks" in navigator 跳过逻辑等于裸奔:
- 前端可降级为
localStorage+ 时间戳标记(仅提示,不防覆盖) - 服务端必须做幂等校验:前端写请求带上
requestId或版本号(如_rev),后端比对后拒绝重复或过期写入 - 不要试图用
storage事件模拟锁——它只能通知,不能阻塞










