浏览器中不存在真正共享线程,需通过BroadcastChannel通知、localStorage乐观锁、IndexedDB事务及服务端协调实现跨页面状态同步与锁定。

共享线程本身在浏览器环境中并不存在——Web Worker 是独立线程,无法直接共享内存或变量;而主线程是单线程的,所谓“共享线程”通常是对多页面间协同机制的误称。真正可行的是通过 跨页面通信 + 一致的状态管理策略 来模拟同步与锁定行为。
用 BroadcastChannel 实现轻量级跨页面通知
BroadcastChannel API 允许同源下不同页面(含标签页、iframe、Worker)之间发送消息,适合广播“数据即将修改”“锁已释放”等信号。
- 每个页面创建同名 channel,如
new BroadcastChannel('cart-lock') - 写操作前先发
{ type: 'acquire', key: 'user-profile', timestamp: Date.now() } - 其他页面监听到该消息,可暂停本地编辑、显示“他人正在编辑”提示
- 操作完成后发
{ type: 'release', key: 'user-profile' },解除阻塞
用 localStorage + 时间戳实现简易乐观锁
localStorage 虽不能触发跨页面事件,但配合 storage 事件和版本标记,可构建无中心服务的冲突检测逻辑。
- 将数据存为对象:
{ value: ..., version: 1698765432100, updatedAt: '2023-10-30T09:20:32Z' } - 读取时记录当前 version;提交前比对 localStorage 中的 version 是否一致
- 不一致则拒绝写入,提示“数据已被其他页面更新”,并加载最新值供用户合并
- 利用
window.addEventListener('storage', handler)在其他页面变更时自动刷新本地缓存
用 IndexedDB 实现带事务与游标控制的强一致性
当需要真实事务语义(如库存扣减不可回滚),IndexedDB 是目前浏览器中唯一支持多对象存储、版本升级与显式事务的方案。
- 所有页面共用同一数据库,使用
transaction(..., 'readwrite')确保原子性 - 对关键资源(如订单号生成器)单独建表,用
put()+get()配合自增 ID 或 UUID 避免重复 - 写操作前尝试获取独占锁:向
locksobjectStore 插入唯一键(如'profile-lock'),失败即表示已被占用 - 锁应带 TTL 字段,防止页面崩溃后锁永久滞留;可用定时器或下次启动时清理过期锁
避免过度设计:优先用服务端协调
浏览器端的“锁定”本质是妥协方案,延迟、竞态、崩溃场景下难以 100% 可靠。
- 高频协作场景(如多人协作文档)应依赖 WebSocket 或 Server-Sent Events 主动推送状态
- 将最终一致性交给后端:前端只负责展示+本地暂存,所有写请求走统一 API,由服务端做分布式锁(Redis SETNX)或版本校验
- 前端保留离线能力:用 Workbox 缓存接口、用 background sync 延迟重试,而非自行维护复杂锁逻辑

















