前端可以玩“锁”🔐了
大家好,我是CC,在这里欢迎大家的到来~
“锁”经常使用在多进程的语言理和数据库事务的架构当中,现在 Web API 当中也提供了“锁”- Web Locks API。
领域
在浏览器多标签页或 worker 中运行的脚本中获取锁,执行工作时保持锁,最后释放锁。
锁的范围仅限于同一源内
请求锁
同一源下,当持有锁时,其他相同锁的请求将排队,仅当锁被释放时第一个排队的请求才会被授予锁。
回调函数执行完毕后锁会自动释放
navigator.locks.request('mylock', {}, async (lock) => {
console.log(lock);
});
在这里我们能看到 request 方法的第二个参数(可选),可以在请求锁时传递一些选项,这个我们在后边会介绍到。
监控锁
判断锁管理器的状态,有利于调试;返回结果是一个锁管理器状态的快照,标识了持有锁和请求中的锁的有关数据,像名称、client_id和模式。
navigator.locks.query().then((locks) => {
console.log(locks);
});
实现
接下来将使用请求锁的可选参数实现以下内容:
从异步任务返回值
request() 方法本身返回一个 Promise,一旦锁被释放,该 Promise 就会 resolve。
const result = await navigator.locks.request('ccmama'}, async (lock) => {
// 任务
return data;
});
// 拿到内部回调函数返回的 data
console.log(result);
共享锁和独占锁模式
配置项 mode 默认是 'exclusive',可选项还有 'shared'。
锁只能有一个持有者,但是可以同时授权多个共享。
在读写模式中经常使用 'shared' 模式进行读取,'exclusive' 模式用于写入。
navigator.locks.request('ccmama', {
mode: 'shared',
}, async (lock) => {
// 任务
});
📢
持有 'exclusive' 锁,同名 'exclusive' 锁排队等候
持有 'exclusive' 锁,同名 'shared' 锁排队等候
持有 'shared' 锁,同名 'shared' 锁也可访问同一资源
持有 'shared' 锁,同名 'exclusive' 锁排队等候
条件获取
配置项 ifAvailable 默认 false,当设置 true 时锁请求仅在不需要排队时才会被授予,也就是说在任务没有其他等待的情况下锁请求才会被授予,否则返回 null。
navigator.locks.request('ccmama', { ifAvailable: true }, async lock => {
if (!lock) return;
// 任务
});
注意:同名锁
防止死锁的应急通道
配置项 steal 默认 false,当设置为 true 时任何持有的同名锁将被释放,并且请求将被授权,抢占任何排队中的锁请求。
navigator.locks.request('ccmama', { steal: true }, async lock => {
// 任务
});
⚠️
使用要小心。之前在锁内运行的代码会继续运行,并且可能与现在持有锁的代码发生冲突。
中止锁定请求
配置项 signal 是 AbortSignal 类型;如果指定并且 AbortController 被中止,则锁请求将被丢弃。
try {
const controller = new AbortController();
setTimeout(() => controller.abort(), 400);
navigator.locks.request('ccmama', { signal: controller.signal }, async lock => {
// 任务
});
} catch(ex) {}
// 或
try {
navigator.locks.request('ccmama', { signal: AbortSignal.timeout(1000) }, async lock => {
// 任务
});
} catch(ex) {}
⚠️
超时时会报出一个异常错误,需要使用 try catch 捕获
参考文章
可能理解并不一定到位,欢迎交流。
来源:juejin.cn/post/7382640456109490211