LockManager: request() 方法

Baseline 已廣泛支援

此特性已經十分成熟,可在許多裝置和瀏覽器版本上使用。自 2022 年 3 月起,它已在各瀏覽器中可用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

注意:此功能在 Web Workers 中可用。

LockManager 介面的 request() 方法用於請求一個 Lock 物件,並提供指定其名稱和特性的引數。請求到的 Lock 會被傳遞給一個回撥函式,而該方法本身會返回一個 Promise。該 Promise 會在鎖釋放後,隨著回撥函式的執行結果而解析(或拒絕),或者在請求被中止時拒絕。

options 引數的 mode 屬性可以是 "exclusive"(獨佔)或 "shared"(共享)。

當某個程式碼例項應該獨佔資源時,請求一個 "exclusive" 鎖。這適用於標籤頁和 worker 中的程式碼。使用此模式來表示對資源的互斥訪問。當持有某個名稱的 "exclusive" 鎖時,任何其他具有相同名稱的鎖都無法被持有。

當多個程式碼例項可以共享對資源的訪問時,請求一個 "shared" 鎖。當持有某個名稱的 "shared" 鎖時,其他具有相同名稱的 "shared" 鎖可以被授予,但具有該名稱的 "exclusive" 鎖無法被持有或授予。

這種共享/獨佔鎖模式在資料庫事務架構中很常見,例如,它允許多個讀取器同時訪問(每個讀取器請求一個 "shared" 鎖),但只允許一個寫入器(一個 "exclusive" 鎖)。這被稱為“讀者-寫者”模式。在 IndexedDB API 中,這表現為 "readonly""readwrite" 事務,它們具有相同的語義。

語法

js
request(name, callback)
request(name, options, callback)

引數

name

您想要請求的鎖的識別符號。

options 可選

一個描述您想要建立的鎖的特性的物件。有效值為:

mode 可選

可以是 "exclusive"(獨佔)或 "shared"(共享)。預設值為 "exclusive"

ifAvailable 可選

如果為 true,則僅當鎖尚未被持有(可用)時,才會授予鎖請求。如果無法授予,回撥函式將以 null 而非 Lock 例項的形式被呼叫。預設值為 false

steal 可選

如果為 true,則會釋放所有具有相同名稱的已持有鎖,並授予當前請求,從而優先於任何排隊中的相同請求。預設值為 false

警告: 請謹慎使用!先前在鎖內執行的程式碼將繼續執行,並且可能會與當前持有鎖的程式碼發生衝突。

signal 可選

一個 AbortSignalAbortControllersignal 屬性);如果指定了並且 AbortController 被中止,則如果鎖請求尚未被授予,它將被丟棄。

回撥

在鎖被授予時呼叫的方法。當回撥函式返回(或丟擲異常)時,鎖會自動釋放。通常回調函式是一個非同步函式,這會導致只有在非同步函式完全完成後鎖才會被釋放。

返回值

一個 Promise,它會在鎖釋放後、隨著回撥函式的執行結果而解析(或拒絕),或者在請求被中止時拒絕。

異常

此方法可能返回一個拒絕的 Promise,拒絕原因是一個 DOMException,其型別可能為以下之一:

InvalidStateError DOMException

當環境的文件不完全處於活動狀態時丟擲。

SecurityError DOMException

當無法為當前環境獲取鎖管理器時丟擲。

NotSupportedError DOMException

name 以連字元(-)開頭,同時設定了 stealifAvailable 選項為 true,或者當 signal 選項存在且 stealifAvailable 選項之一為 true 時丟擲。

AbortError DOMException

signal 選項存在且被中止時丟擲。

示例

通用示例

以下示例展示了 request() 方法的基本用法,其中回撥函式為一個非同步函式。一旦回撥函式被呼叫,此源上的任何其他正在執行的程式碼都無法持有 my_resource,直到回撥函式返回為止。

js
await navigator.locks.request("my_resource", async (lock) => {
  // The lock was granted.
});

mode 示例

以下示例展示瞭如何為讀者和寫者使用 mode 選項。

請注意,這兩個函式都使用名為 my_resource 的鎖。do_read() 請求一個 'shared' 模式的鎖,這意味著跨不同事件處理程式、標籤頁或 worker 的多個呼叫可能會同時發生。

js
async function do_read() {
  await navigator.locks.request(
    "my_resource",
    { mode: "shared" },
    async (lock) => {
      // Read code here.
    },
  );
}

do_write() 函式使用相同的鎖,但模式為 'exclusive',這將延遲 do_read()request() 呼叫的執行,直到寫入操作完成。這同樣適用於事件處理程式、標籤頁或 worker。

js
async function do_write() {
  await navigator.locks.request(
    "my_resource",
    { mode: "exclusive" },
    async (lock) => {
      // Write code here.
    },
  );
}

ifAvailable 示例

要僅在鎖未被佔用時獲取鎖,請使用 ifAvailable 選項。在此函式中,await 意味著該方法在回撥函式完成之前不會返回。由於該鎖僅在可用時才會被授予,因此此呼叫避免了需要等待鎖在別處被釋放。

js
await navigator.locks.request(
  "my_resource",
  { ifAvailable: true },
  async (lock) => {
    if (!lock) {
      // The lock was not granted - get out fast.
      return;
    }

    // The lock was granted, and no other running code in this origin is holding
    // the 'my_res_lock' lock until this returns.
  },
);

signal 示例

要僅為鎖等待一小段時間,請使用 signal 選項。

js
const controller = new AbortController();
// Wait at most 200ms.
setTimeout(() => controller.abort(), 200);

try {
  await navigator.locks.request(
    "my_resource",
    { signal: controller.signal },
    async (lock) => {
      // The lock was acquired!
    },
  );
} catch (ex) {
  if (ex.name === "AbortError") {
    // The request aborted before it could be granted.
  }
}

規範

規範
Web Locks API
# api-lock-manager-request

瀏覽器相容性