无需登录 数据私有 本地保存

Web Locks API 探索器 - 跨标签页资源协调

93
0
0
0

常见问题

什么是Web Locks API?

Web Locks API是浏览器提供的原生分布式锁机制,允许Web应用在多个标签页、iframe和Worker之间协调对共享资源的访问。通过navigator.locks.request(name, options, callback)方法可以获取一个命名锁,同一名称的锁在整个浏览器中全局互斥或共享。Web Locks API解决了多标签页应用场景中的数据竞争问题,是浏览器原生提供的跨上下文同步原语,无需依赖localStorage、BroadcastChannel或服务端来实现简单的锁机制。

独占锁和共享锁有什么区别?

独占锁(exclusive)在同一时刻只能被一个浏览上下文持有,获取时如果锁已被占用则阻塞等待。共享锁(shared)允许多个浏览上下文同时持有同一锁。两者的核心区别在于互斥关系:独占锁与所有其他锁(包括其他独占锁和共享锁)互斥;共享锁与独占锁互斥,但与其他共享锁不互斥。这种设计类似于数据库中的读写锁,共享锁允许多个读者并发访问,独占锁确保写者的排他性。

ifAvailable选项的作用是什么?

ifAvailable是navigator.locks.request()方法的选项之一,设置为true时,如果锁当前不可用则立即返回false而不阻塞等待。这适用于非关键操作,例如尝试性地更新缓存、检查资源状态等,这些操作不值得阻塞当前页面的执行流程。使用ifAvailable获取锁的请求不会进入锁的等待队列,获取失败后也不会影响后续的正常锁请求。它是一种乐观锁获取策略。

steal选项有什么风险?

steal选项允许强制从当前持有者手中窃取锁的所有权。被窃取的标签页会在锁回调中收到AbortError,这意味着它正在进行的锁保护操作会被中断。风险在于:如果持有者在被窃取时正在执行数据修改操作,数据可能处于不一致的中间状态;被窃取的标签页可能没有任何机会执行清理或回滚逻辑。因此,steal选项应仅在紧急场景(如用户明确要求取消操作)中使用,并且使用前应确保被中断的操作具有幂等性或可恢复性。

AbortSignal如何实现锁获取超时?

通过AbortController和AbortSignal可以实现锁获取的超时控制。首先创建一个AbortController实例,然后设置setTimeout在指定时间后调用controller.abort()。将controller.signal作为navigator.locks.request()的signal选项传入。当超时触发abort()时,如果锁请求还在等待队列中,会立即取消并抛出AbortError;如果锁已经获取成功,则abort()不会影响已持有的锁。这种模式可以防止锁请求无限期等待,提升应用的响应性。

Web Locks API的浏览器兼容性如何?

Web Locks API在桌面浏览器中的支持情况:Chrome 69及以上版本完全支持,Edge 79及以上版本完全支持,Firefox 96及以上版本完全支持,Safari 15.4及以上版本支持。移动端浏览器中,Chrome for Android完全支持,Safari iOS 15.4及以上版本支持。对于不支持Web Locks API的浏览器,可以使用基于localStorage的轮询锁或服务端锁作为降级方案。本工具在不支持的环境下会显示兼容性提示。

Web Locks与localStorage锁有什么区别?

基于localStorage的锁机制依赖于轮询检测(定期读取localStorage中的标志位)和同源策略,存在多个问题:轮询间隔影响响应速度、标签页关闭时标志位可能残留导致死锁、跨iframe的localStorage访问可能受到沙箱限制、无法处理进程级别的并发(如同一浏览器的多个进程)。Web Locks API由浏览器内核管理,支持事件驱动的通知机制、自动清理(标签页关闭时锁自动释放)、跨iframe/Worker的全局协调,可靠性远高于localStorage方案。

Web Locks API有哪些实际应用场景?

Web Locks API的典型应用场景包括:多标签页表单提交防护(确保用户不会在多个标签页中重复提交同一表单)、客户端数据缓存协调(确保多个标签页不会同时进行缓存刷新)、支付和交易防重复(确保同一笔交易不会被多次处理)、离线数据同步(确保多个标签页不会同时向服务端同步数据)、Web Worker任务调度(协调多个Worker对共享数据的访问)、浏览器扩展与页面的通信协调等。本工具内置的预设场景覆盖了其中几种典型用法。

如何避免Web Locks中的死锁?

Web Locks API本身不提供死锁检测机制。避免死锁的最佳实践是:始终以固定的全局顺序获取多个锁(如按字母顺序排列锁名称),确保所有标签页都遵循相同的获取顺序;设置合理的超时时间,避免锁请求无限期等待;尽量减少同时持有的锁数量,缩小锁的作用范围;在设计上避免需要同时持有两个以上锁的场景。如果应用复杂度较高,考虑使用更高级的协调机制如事务性操作或消息队列。

navigator.locks.query()返回什么信息?

navigator.locks.query()返回一个Promise,解析为一个LockManagerSnapshot对象,包含两个数组:held数组包含当前所有被持有的锁,每个条目有name(锁名称)、mode(锁模式)、clientId(持有锁的标签页ID)、requests(与该锁关联的等待请求列表)等字段;pending数组包含所有在等待队列中排队的锁请求,每个条目有name(请求的锁名称)、mode(请求的锁模式)、clientId(发起请求的标签页ID)等字段。这些信息可以帮助开发者全面了解当前浏览器中的锁分配状态。