必须显式指定 mode: 'exclusive' 才能防止写冲突;锁名须带业务唯一标识且 url-safe;await navigator.locks.request() 回调必须是 async 且 await 事务完成;safari 不支持,需服务端幂等降级。

必须显式指定 mode: 'exclusive' 才能防止写冲突
Web Locks API 默认行为在旧版 Chrome 中会静默 fallback 到 shared 模式,而 shared 锁允许多个标签页同时进入回调——这等于没锁。写操作必须强制设为 exclusive,否则竞态照旧。
常见错误写法:navigator.locks.request('cart', () => { ... })(没传配置对象)或 navigator.locks.request('cart', { mode: 'shared' }, ...)。
正确写法应始终包含显式声明:
await navigator.locks.request('cart-user-123', {
mode: 'exclusive',
ifAvailable: true
}, async () => {
// 写逻辑
});
-
ifAvailable: true防止 UI 卡死:锁被占用时立即返回undefined,而不是无限等待 - 可进一步加超时控制:
signal: AbortSignal.timeout(3000) - 读操作才考虑
shared;所有“读→改→写”闭环必须用exclusive
锁名必须带业务唯一标识且 URL-safe
用 'cart' 或 'db-write' 这类泛化锁名,会导致所有用户、所有资源共用一把锁——A 用户保存购物车时,B 用户连修改个人头像都会被阻塞。
锁名本质是作用域标识符,不是随便起的变量名。它必须满足:
- 按资源粒度命名,例如:
cart-user-123、note-789、theme-config(仅全站统一配置才无 ID) - 禁止含空格、斜杠、控制字符;建议长度 ≤64 字符
- 禁用时间戳或随机数:
cart-${Date.now()}或cart-${Math.random()}会让锁名每次不同,互斥失效 - 用户维度不能漏掉:
cart-789不如cart-user-123-item-789精准(视业务隔离需求而定)
await navigator.locks.request() 必须 await,且回调必须返回 Promise
不 await navigator.locks.request(),等于锁申请完立刻释放,后续 IndexedDB 操作完全不受控。更隐蔽的坑是:回调里只做同步操作或返回字符串,锁也会在函数退出瞬间释放——此时 put() 可能还没真正落盘。
典型错误:
// ❌ 错误:没 await,且回调无 async
navigator.locks.request('cart', () => {
db.transaction('cart', 'readwrite').objectStore('cart').put(data);
});
正确结构必须是:
await navigator.locks.request('cart-user-123', {
mode: 'exclusive',
ifAvailable: true
}, async () => {
const tx = db.transaction('cart', 'readwrite');
const store = tx.objectStore('cart');
await store.put(data, key);
await tx.done; // 关键:等事务真正持久化完成
});
- 回调必须是
async () => {}或显式return Promise.resolve() -
await tx.done不可省略:仅tx.commit()不保证写入落地,锁提前释放会导致 ABA 覆盖 - 别在锁回调里做耗时操作(加密、大数组遍历、上传),这些应移出锁外
Safari 不支持,降级不是可选而是硬性要求
截至 iOS 17.5 / macOS 14.5,Safari 仍无 Web Locks API 实现痕迹。仅靠 if ('locks' in navigator) 就跳过逻辑,等于在 Safari 里裸奔。
生产环境必须提供 fallback:
- 服务端幂等是底线:每个写请求附带客户端生成的
requestId,后端据此拒绝重复处理 - 前端轻量提示:用
localStorage+storage事件模拟冲突检测,例如存lock:cart-123时间戳,监听到同名变更即弹出“其他窗口正在编辑” - 注意:这种模拟不是强一致,仅作友好提示;强一致性场景(如库存扣减)必须后端配合 ETag 或
_rev字段做乐观并发校验
真正容易被忽略的是锁的作用域边界:私有模式(隐身窗口)、不同源、跨设备,全部不共享锁——你测试时用两个普通标签页成功了,不代表用户在 Safari + Chrome + 移动端同时操作也安全。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











