• 作者:老汪软件技巧
  • 发表时间:2024-09-04 17:13
  • 浏览量:

在逛MDN文档的时候瞄了一眼Lock板块,惊奇的发现,咱竟然也有“锁”的概念?抱着好奇心,我去研究了一波其用法,和应用场景,接下来众客官听我细细道来。

在此之前先放个文档LOCK。

如果懒得查看文档就看我一步步解析吧!

执行机制

本质上是一种用于在应用程序中管理资源同步的机制。它允许我们异步地获取、持有和释放对特定资源的锁,以确保在同一网页源中的不同上下文(如窗口、不同线程等)能有序地访问共享资源,从而避免潜在的数据竞争和冲突。

注意,上文的异步是指在待锁的过程中可以继续执行其他任务,倘若锁被成功获取,则进行相关资源操作;否则,将进入等待状态,直到锁可用。

以上的种种机制既保证了资源使用的安全性,又避免了阻塞问题。

代码示例

常用的API解析

一个简单的例子:

async function do_read() {
  await navigator.locks.request(
    "my_resource",
    { mode: "shared" },
    async (lock) => {
      // 执行锁后的逻辑操作
    },
  );
}

结合web-worker + indexDB实现数据独占锁

// lock.html
<script>
      // 初始化 IndexedDB
      function initDB(dbName) {
        const request = indexedDB.open(dbName, 1);
        request.onerror = (event) => {
          console.error('error: ' + event.target.errorCode);
        };
        request.onsuccess = (event) => {
          console.log('初始化成功!');
        };
        request.onupgradeneeded = (event) => {
          const db = event.target.result;
          db.createObjectStore('items', { keyPath: 'id', autoIncrement: true });
        };
      }
      // 创建并启动 Web Workers
      function startWorkers(workerUrl, count) {
        for (let i = 0; i < count; i++) {
          const worker = new Worker(workerUrl);
          worker.postMessage({ dbName: 'myDatabase' });
        }
      }
      initDB('myDatabase');
      startWorkers('js/worker.js', 2); // 启动两个 Worker
    script>

上面代码:初始化indexDB,并开启两个worker线程,模拟数据竞争。

// js/worker.js
self.onmessage = function (e) {
  const dbName = e.data.dbName
  const lockName = dbName + '-lock'
  function updateDatabase() {
    try {
      // 请求独占锁  
      navigator.locks.request(lockName, { mode: 'exclusive' }, lock => {
        console.log(lock)
        // 在锁的保护下访问数据库  
        const request = indexedDB.open(dbName, 1)
        request.onerror = function (event) {
          console.error("worker线程中读取indexDB失败:", event.target.errorCode)
        }
        request.onsuccess = function (event) {
          const db = event.target.result
          const tx = db.transaction('items', 'readwrite')
          const store = tx.objectStore('items')
          // 假设我们添加一条新数据
          const item = { name: 'Item ' + Math.random() }
          store.add(item)
          tx.oncomplete = function () {
            console.log('添加成功', lock.name)
          }
          tx.onerror = function (event) {
            console.error('error:', event.target.errorCode)
          }
        }
      })
    } catch (error) {
      console.error('error lock:', error)
    }
  }
  updateDatabase()
}

利用锁的特性,加以保护IndexedDB数据库的访问。

应用场景

多窗口实行数据锁,解决在这种内部多小窗口化中的数据竞争。

需要注意的是,由于Web Locks API目前主要在Chrome和基于Chromium的浏览器中有实验性支持,并且可能还未成为正式标准,因此其应用场景可能有限且基于实验性实现。