Web Locks API 解决什么问题?多标签页如何避免重复任务?
简化版
Web Locks API 允许同源多个标签页或 Worker 竞争一把命名锁,用来避免重复刷新 token、重复同步离线队列、重复跑定时任务等问题。它适合浏览器内同源并发协调,但要考虑兼容性、锁超时、任务失败和降级方案。
详细版
多标签页问题:
- 3 个标签页同时刷新 token,造成重复请求。
- 多个标签页同时上传离线队列,产生重复提交。
- 多个页面都跑定时同步,浪费资源。
Web Locks 用法:
- 调用
navigator.locks.request('lock-name', callback)。 - 同一时间只有拿到锁的上下文执行 callback。
- 执行结束后释放锁。
- 可设置非阻塞模式或查询锁状态。
注意点:
- 兼容性要确认。
- 关键业务仍需服务端幂等。
- 任务要有超时和失败处理。
完整版教学
一、多标签页会制造本地并发
很多前端代码默认“一个用户只有一个页面”。现实中用户可能打开 5 个标签页,每个标签页都有定时器、登录态刷新、离线队列同步和消息拉取。如果不协调,就会出现重复请求和状态冲突。
Web Locks API 提供浏览器原生的同源锁机制,让多个标签页约定:同一时间只有一个执行某个关键任务。它像浏览器里的轻量分布式锁,只不过范围限制在同源上下文。
Tab A、Tab B、Tab C
└─ 竞争 lock: sync-offline-queue
└─ 只有一个 Tab 执行同步
二、基本用法是请求命名锁
navigator.locks.request 接收锁名和回调。拿到锁后执行异步任务,回调结束后锁释放。其他请求同一锁的上下文会等待或按配置放弃。
await navigator.locks.request('refresh-token', async () => {
const token = await refreshToken()
saveToken(token)
})
锁名要稳定且语义清楚,例如 refresh-token、sync-outbox、daily-cleanup。不要把用户输入直接拼成无限多锁名,避免管理混乱。
三、它适合浏览器内任务协调
典型场景是 token 刷新。假设用户打开 4 个标签页,token 还有 1 分钟过期。没有锁时,4 个页面可能同时刷新;有锁时,只有一个页面刷新,其他页面等待或监听结果。
数字例子:一个接口刷新 token 成本 300ms,4 个标签页同时刷会打 4 次请求。用户量 10000 时,瞬间可能放大到 40000 次请求。锁能把同一浏览器内的重复请求压到 1 次,但跨设备仍需服务端保护。
| 场景 | Web Locks 作用 | 仍需后端做什么 |
|---|---|---|
| 刷新 token | 同浏览器只刷新一次 | token 轮换安全 |
| 离线队列 | 避免多标签重复上传 | 幂等去重 |
| 定时清理 | 只让一个页面执行 | 容忍未执行 |
| 后台同步 | 降低重复任务 | 状态一致性 |
四、锁不是服务端幂等的替代品
Web Locks 只能协调同一浏览器同源页面。用户换浏览器、换设备、清理环境,锁都不起作用。攻击者也可以绕过前端直接请求接口。因此涉及订单、支付、提交、核销等关键动作,服务端仍必须幂等。
可以把 Web Locks 看成“减少正常情况下的重复”,服务端幂等是“保证异常情况下也正确”。两者层级不同,不能互相替代。
五、任务失败和超时要处理
如果拿到锁的任务卡住,其他页面可能一直等待。实际代码要给网络请求设置超时,并在失败时释放锁。回调抛错后锁会释放,但业务状态可能需要标记失败并允许后续重试。
拿锁 → 执行任务
├─ 成功:广播结果
├─ 失败:记录并允许重试
└─ 超时:中断任务并释放锁
如果配合 BroadcastChannel,拿锁页面完成后可以广播结果,其他页面就不用重复请求。
六、兼容性和降级要准备
Web Locks 并不是所有环境都完美支持。生产使用前要查目标浏览器和 WebView 支持情况。降级方案可以用 localStorage 标记、BroadcastChannel 协商、SharedWorker,或简单接受重复请求但依赖服务端幂等。
对于低风险任务,兼容性不足时可以直接多执行几次;对于高价值提交,绝不能只靠 Web Locks,后端唯一约束和幂等 ID 是底线。
记忆钩子:Web Locks 是“同源多标签页的排队号”,能减少重复任务,但不能保证全世界只有一次。
七、常见误区与追问
- 误区:Web Locks 可以解决所有重复提交。 它只管同源浏览器上下文,服务端仍要幂等。
- 误区:拿到锁后任务一定会成功。 网络、权限和业务错误仍可能失败,要有超时和重试。
- 误区:所有浏览器都支持 Web Locks。 需要检查兼容性,并准备降级方案。
- 追问:多标签页刷新 token 怎么做? 用
refresh-token锁限制单页刷新,完成后广播或共享新 token。 - 追问:离线队列为什么还要服务端幂等? 多设备、重试和绕过前端都可能重复提交,后端必须按业务 ID 去重。
- 追问:和 BroadcastChannel 怎么配合? Web Locks 选出执行者,BroadcastChannel 通知其他页面结果。
八、加强记忆
Web Locks API 用“同源、命名锁、少重复、后端兜底”来记。它适合协调多标签页 token 刷新、离线同步和定时任务,但边界只在浏览器内。真正关键的业务一致性仍靠服务端幂等,前端锁只是减压和改善体验。