Web Locks API 允许在一个选项卡或工作线程中运行的脚本异步获取锁,在执行工作时保持它,然后释放它。持有时,在同一源中执行的其他脚本都无法获取相同的锁,这允许在多个选项卡或工作线程中运行的 Web 应用程序协调工作和资源的使用。
概念
"锁"是一个抽象概念,代表着潜在的共享资源,这些资源由Web应用程序用特定的名称进行标识。例如,如果一个Web应用程序在多个选项卡中运行,并希望确保只有一个选项卡在网络和索引数据库之间同步数据,那么每个选项卡都可以尝试获取名为"my_net_db_sync"的锁,但只有成功获取锁的选项卡才能进行数据同步。比如最近在实现多个tab共享webSocket的场景,如何在多个tab的情况下只创建一个长连接,避免资源浪费呢?
Web Locks使用
await do_something_without_lock();
await navigator.locks.request("my_resource", async (lock) => {
// 开始执行
await do_something();
await do_something_else();
// 执行所有的异步操作后浏览器会释放该锁
});
await do_something_else_without_lock();
当多个tab请求一个资源锁时,只会在一个tab选项卡获得锁,然后执行完其他浏览器才能取得执行权限。
请求锁时可以传递几个选项:
- mode:默认模式为“独占”,但可以指定“共享”。锁只能有一个“独占”持有者,但可以同时授予多个“共享”请求。这可以用来实现读-写锁。
- signal:可以传入一个 AbortSignal,允许中止锁定请求。这可用于实现请求超时。
- ifAvailable:如果指定,如果不等待就无法立即授予锁定,则锁定请求将失败。回调是通过 调用的null。
监控
可以使用 navigator.locks.query()
方法检测锁管理器的状态。
死锁
当一个进程由于每个部分都在等待一个无法满足的请求而无法再取得进展时,就会发生死锁。在复杂的用例中,例如,如果无序地请求多个锁,则此API可能会发生这种情况。如果标签 1 持有锁 A,标签 2 持有锁 B,则标签 1 也试图获取锁 B,标签 2 也试图获取锁 A,这两个请求都不能被授予。Web应用程序可以通过多种策略避免这种情况,例如确保锁请求不嵌套,或者始终有序,或者有超时。这种死锁只影响锁本身和依赖于它们的代码。浏览器、其他标签页和页面中的其他脚本不受影响。