Web Locks API

W3C 工作草案

关于本文档的更多信息
此版本:
https://www.w3.org/TR/2025/WD-web-locks-20250924/
最新发布版本:
https://www.w3.org/TR/web-locks/
编辑草稿:
https://w3c.github.io/web-locks/
历史版本:
历史记录:
https://www.w3.org/standards/history/web-locks/
测试套件:
https://github.com/web-platform-tests/wpt/tree/master/web-locks
反馈:
GitHub
规范内反馈
编辑:
(Mozilla)
前任编辑:
(Google Inc.)

摘要

本文档定义了一个 Web 平台 API,允许脚本异步获取某个资源的锁,在执行任务期间持有该锁,然后释放锁。锁被持有时,来自同一源的其他脚本无法获取对同一资源的锁。这使得 Web 应用中的上下文(窗口、工作者)能够协调资源的使用。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 发布文档列表及本技术报告的最新版本可在 W3C 标准和草案索引中找到。

本文档由 Web 应用工作组 按照 推荐流程 作为工作草案发布。 作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一个草稿文档, 可能随时被更新、替换或废弃, 不应将本文件作为正式成果引用,仅可视为正在进行的工作。

本文档由遵循 W3C 专利政策的小组制作。W3C 维护着关于本小组成果的专利公开列表;该页面还包括专利披露说明。如个人知晓某专利包含必要权利要求,必须根据W3C 专利政策第6节进行披露。

本文档受 2025年8月18日 W3C 流程文档 管辖。

1. 简介

本节为非规范性内容。

脚本可针对特定的资源名称模式发起锁请求。调度算法会根据当前和先前的请求状态,最终授予锁请求。即为已被授予的请求;它具有资源名称模式,并以对象的形式返回给脚本。只要锁被持有,可能会阻止其他锁请求被授予(取决于名称和模式)。脚本可释放锁,此时可能允许其他锁请求被授予。

该 API 提供了可选功能,按需使用,包括:

协作协调在共享agent存储桶范围内进行;这可能跨越多个agent 集群

注意: Agent大致对应于窗口(标签页)、iframe 和 worker。Agent 集群在某些用户代理实现中对应于独立进程。

1.1. 用法概述

该 API 的用法如下:

  1. 请求锁。

  2. 在异步任务中持有锁进行操作。

  3. 任务完成后锁自动释放。

API 的基本用法如下:

navigator.locks.request('my_resource', async lock => {
   // 已获取锁。
   await do_something();
   await do_something_else();
   // 现在锁将被释放。
});

在异步函数中,可以使用 await 等待锁请求:

// 请求锁之前。
await navigator.locks.request('my_resource', async lock => {
   // 已获取锁。
   await do_something();
   // 现在锁将被释放。
});
// 锁释放之后

1.2. 应用动机与场景

一个基于 Web 的文档编辑器将状态存储在内存中以加快访问,并将更改(作为一系列记录)持久化到诸如Indexed Database API之类的存储 API,以增强可靠性和离线使用,同时同步到服务器以支持跨设备使用。当同一文档在两个标签页中被打开编辑时,必须在标签之间协调操作,例如只允许一个标签进行更改或同步文档。需要协调哪个标签处于活动状态(并将内存状态与存储 API 同步),并在活动标签离开(导航、关闭、崩溃)时让另一个标签成为活动标签。

在数据同步服务中,会指定一个“主标签页”。只有该标签页应执行某些操作(如网络同步、清理队列数据等)。它持有锁且从不释放。其他标签页可以尝试获取锁,这些尝试将被排队。如果“主标签页”崩溃或关闭,则其他标签页之一将获得锁并成为新的主标签页。

Indexed Database API定义了一个事务模型,允许在同一源下的多个命名存储分区间进行共享读和独占写访问。将这一概念作为原语暴露出来,允许基于资源可用性调度任何 Web 平台活动,例如允许为其他存储类型(如 Caches [Service-Workers])组合事务,跨存储类型,甚至跨非存储 API(如网络请求)。

2. 基本概念

本规范中:

用户代理拥有一个锁任务队列,其结果为启动新并行队列

以下步骤入队所用的任务来源Web Locks 任务来源

2.1. 资源名称

资源名称是由 Web 应用选择的JavaScript 字符串,用于表示抽象资源。

资源名称除了用于调度算法外没有外部意义,但在共享同一agent存储桶之间是全局的。Web 应用可自由选择资源命名方案。

为模拟 [IndexedDB-2]中针对命名数据库下的命名存储进行事务锁定,脚本可将资源名称组合为:
encodeURIComponent(db_name) + '/' + encodeURIComponent(store_name)

以 U+002D 连字符(-)开头的资源名称为保留项;请求此类名称将导致抛出异常。

2.2. 锁管理器

锁管理器封装锁请求的状态。每个存储桶通过与 Web Locks API 相关联的存储瓶包含一个锁管理器

注意: 共享同一存储桶的页面和 worker(agent)在同一用户代理下即使处于不同的浏览上下文,也共享同一个锁管理器

获取锁管理器,给定一个环境设置对象environment,执行以下步骤:
  1. map获取本地存储瓶映射的结果,参数为environment和"web-locks"。

  2. 如果map为失败,则返回失败。

  3. bottlemap关联的存储瓶

  4. 返回bottle关联的锁管理器

此处需完善与[Storage]的集成,包括如何从给定环境正确获取锁管理器。

2.3. 锁模式与调度

模式为"exclusive"或"shared"。模式可用于模拟常见的读者-写者锁模式。如果持有"exclusive"锁,则不能授予同名的其他锁。如果持有"shared"锁,则可以授予其他同名的"shared"锁,但不能授予"exclusive"锁。API 默认模式为"exclusive"。

其他属性如超时、公平性等也可能影响调度。

2.4.

表示对共享资源的独占访问。

具有agent,即agent

具有clientId,为不透明字符串。

具有manager,即锁管理器

具有name,即资源名称

具有mode,为"exclusive"或"shared"。

具有waiting promise,即一个 Promise。

具有released promise,即一个 Promise。

锁生命周期相关有两个 Promise:
  • 在授予锁时回调隐式或显式提供的 Promise,决定锁持有时长。该 Promise 结算时,锁被释放。称为锁的waiting promise

  • LockManagerrequest()方法返回的 Promise,在锁释放或请求中止时结算。称为锁的released promise

const p1 = navigator.locks.request('resource', lock => {
  const p2 = new Promise(r => {
    // 使用锁并处理 promise...
  });
  return p2;
});

上述示例中,p1released promisep2waiting promise。 注意,大多数代码会将回调实现为async函数,返回的 Promise 为隐式,如下例所示:

const p1 = navigator.locks.request('resource', async lock => {
  // 使用锁的逻辑...
});

上述代码中,waiting promise未命名,但作为匿名async回调的返回值依然存在。 进一步说明:如果回调非async且返回非 Promise,则返回值会被立即解析为 Promise;锁将在下一个微任务中释放,released promise也将在后续微任务中解析。

每个锁管理器有一个持有锁集合,即一个有序集合,包含

lock等待 promise被解决(fulfilled 或 rejected)时,将以下步骤加入锁任务队列

  1. 释放锁lock

  2. 解析lockreleased promise,其值为lockwaiting promise

2.5. 锁请求

锁请求表示对的待处理请求。

锁请求是一个结构体,包含成员 agentclientIdmanagernamemodecallbackpromise,以及signal

锁请求队列队列,包含锁请求

每个锁管理器都有一个锁请求队列映射,它是一个映射,将资源名映射到锁请求队列

要从锁请求队列映射 queueMap中, 根据资源名 name获取锁请求队列,请执行以下步骤:

  1. 如果queueMap[name]不存在,则设置queueMap[name]为一个新的空锁请求队列

  2. 返回queueMap[name]。

当以下步骤返回 true 时,锁请求request被称为可授予

  1. managerrequestmanager

  2. queueMapmanager锁请求队列映射

  3. namerequestname

  4. queue为从queueMap获取name对应的锁请求队列的结果。

  5. heldmanager已持有锁集合

  6. moderequestmode

  7. 如果queue非空request不是queue中的第一个成员,则返回 false。

  8. 如果mode为"exclusive",则当held中没有name等于name时返回 true,否则返回 false。

  9. 否则,mode为"shared";当held中没有mode为"exclusive"且name等于name时返回 true,否则返回 false。

2.6. 锁的终止

每当卸载文档清理步骤针对某个document运行时,使用其agent执行终止剩余锁和请求

当某个agent终止时,使用该 agent 执行终止剩余锁和请求

当前仅适用于 worker,且定义较为模糊,因为没有规范的方法在 worker 终止时运行这些步骤。

要使用agent终止剩余锁和请求,需在锁任务队列排队执行以下步骤

  1. 对于每个锁请求request,其agent等于agent

    1. 中止请求request

  2. 对于每个lock,其agent等于agent

    1. 释放锁lock

3. API

[SecureContext]
interface mixin NavigatorLocks {
  readonly attribute LockManager locks;
};
Navigator includes NavigatorLocks;
WorkerNavigator includes NavigatorLocks;

每个环境设置对象都有一个LockManager对象。

locks getter 的步骤是返回this相关设置对象LockManager对象。

3.2. LockManager

[SecureContext, Exposed=(Window,Worker)]
interface LockManager {
  Promise<any> request(DOMString name,
                       LockGrantedCallback callback);
  Promise<any> request(DOMString name,
                       LockOptions options,
                       LockGrantedCallback callback);

  Promise<LockManagerSnapshot> query();
};

callback LockGrantedCallback = Promise<any> (Lock? lock);

enum LockMode { "shared", "exclusive" };

dictionary LockOptions {
  LockMode mode = "exclusive";
  boolean ifAvailable = false;
  boolean steal = false;
  AbortSignal signal;
};

dictionary LockManagerSnapshot {
  sequence<LockInfo> held;
  sequence<LockInfo> pending;
};

dictionary LockInfo {
  DOMString name;
  LockMode mode;
  DOMString clientId;
};

LockManager实例允许脚本发起锁请求并查询锁管理器的状态。

3.2.1. request() 方法

promise = navigator . locks . request(name, callback)
promise = navigator . locks . request(name, options, callback)

request()方法用于请求锁。

name(第一个参数)是资源名字符串。

callback(最后一个参数)是一个回调函数,在锁被授予时调用,参数为Lock。该回调由脚本指定,通常为async函数。锁会一直持有直到回调函数完成。如果传入的是非 async 回调,则会自动包装为立即 resolve 的 promise,因此锁只会在同步回调期间持有。

返回的promise会在锁释放后以回调的结果 resolve(或 reject),如果请求被中止则 reject。

示例:

try {
  const result = await navigator.locks.request('resource', async lock => {
    // 此处持有锁。
    await do_something();
    await do_something_else();
    return "ok";
    // 锁将在此处释放。
  });
  // |result| 为回调的返回值。
} catch (ex) {
  // 如果回调抛出异常,会在此处捕获。
}

无论回调是正常返回还是抛出异常,锁都会被释放。

可以通过第二个参数指定options字典,callback始终为最后一个参数。

options . mode

mode选项可以为"exclusive"(默认)或"shared"。多个标签页/worker可以以"shared"模式持有同一资源的锁,但只有一个标签页/worker可以以"exclusive"模式持有该资源的锁。

最常见的用途是允许多个读取者同时访问资源,但防止修改。所有读取锁释放后,单个独占写入者可以获取锁进行修改,之后可以再次由独占写入者或更多共享读取者持有。

await navigator.locks.request('resource', {mode: 'shared'}, async lock => {
  // 此处持有锁。其他上下文也可能以共享模式持有锁,
  // 但不会有其他上下文以独占模式持有锁。
});
options . ifAvailable

如果ifAvailable选项为true,则仅在无需等待的情况下授予锁。注意这仍然不是同步的;在许多用户代理中,这需要跨进程通信以判断锁是否可授予。如果无法授予锁,则回调以null调用。(这是预期行为,请求不会被拒绝。)

await navigator.locks.request('resource', {ifAvailable: true}, async lock => {
  if (!lock) {
    // 未获取锁。可在此处做相应处理。
    return;
  }
  // 此处持有锁。
});
options . signal

signal选项可设置为AbortSignal。这允许中止锁请求,例如在未及时授予锁时:

const controller = new AbortController();
setTimeout(() => controller.abort(), 200); // 最多等待 200ms。

try {
  await navigator.locks.request(
    'resource', {signal: controller.signal}, async lock => {
      // 此处持有锁。
  });
  // 此处已完成锁相关操作。
} catch (ex) {
  // 如果定时器触发,|ex| 会是 error name 为 "AbortError" 的 DOMException。
}

如果在锁授予前收到中止信号,则请求 promise 会以AbortError拒绝。一旦锁被授予,signal 将被忽略。

options . steal

如果steal选项为true,则会释放该资源的所有已持有锁(这些锁的released promise会以AbortErrorresolve),并授予该请求,抢占所有排队请求。

如果 web 应用检测到不可恢复的状态——例如某个协调点(如 Service Worker)发现持有锁的标签页不再响应——则可使用此选项“抢占”锁。

谨慎使用steal选项。 使用后,之前持有锁的代码将无法保证自己是唯一访问该资源的上下文。 同样,使用该选项的代码也无法保证其他上下文不会继续以拥有资源的方式执行。 该选项主要用于 web 应用在应用或用户代理出现异常时尝试恢复,此时行为本就不可预测。

request(name, callback)request(name, options, callback) 方法的步骤如下:

  1. 如果未传入options,则令options为一个新的LockOptions字典,成员为默认值。

  2. environmentthis相关设置对象

  3. 如果environment相关全局对象关联 Document不是完全激活,则返回一个以"InvalidStateError"DOMException拒绝的 promise。

  4. manager获取锁管理器(参数为environment)的结果。如果返回失败,则返回一个以"SecurityError"DOMException拒绝的 promise。

  5. 如果name以 U+002D HYPHEN-MINUS (-) 开头,则返回一个以"NotSupportedError"DOMException拒绝的 promise。

  6. 如果options["steal"]和options["ifAvailable"]均为 true,则返回一个以"NotSupportedError"DOMException拒绝的 promise。

  7. 如果options["steal"]为 true 且options["mode"]不是"exclusive",则返回一个以"NotSupportedError"DOMException拒绝的 promise。

  8. 如果options["signal"]存在,且options["steal"]或options["ifAvailable"]为 true,则返回一个以"NotSupportedError"DOMException拒绝的 promise。

  9. 如果options["signal"]存在且已中止,则返回一个以options["signal"]的中止原因拒绝的 promise。

  10. promise新建 promise

  11. 使用promise、当前agentenvironmentidmanagercallbacknameoptions["mode"]、options["ifAvailable"]、options["steal"]和options["signal"]请求锁

  12. 返回promise

3.2.2. query() 方法

state = await navigator . locks . query()

query()方法可用于生成某个源的锁管理器状态快照,允许 web 应用检查其锁使用情况,用于日志或调试。

返回的 promise resolve 为state,一个普通数据结构(即 JSON 格式),结构如下:

{
  held: [
    { name: "resource1", mode: "exclusive",
      clientId: "8b1e730c-7405-47db-9265-6ee7c73ac153" },
    { name: "resource2", mode: "shared",
      clientId: "8b1e730c-7405-47db-9265-6ee7c73ac153" },
    { name: "resource2", mode: "shared",
      clientId: "fad203a5-1f31-472b-a7f7-a3236a1f6d3b" },
  ],
  pending: [
    { name: "resource1", mode: "exclusive",
      clientId: "fad203a5-1f31-472b-a7f7-a3236a1f6d3b" },
    { name: "resource1", mode: "exclusive",
      clientId: "d341a5d0-1d8d-4224-be10-704d1ef92a15" },
  ]
}

clientId字段对应唯一的上下文(frame 或 worker),与Clientid属性值相同。

此数据只是某一时刻锁管理器状态的快照。当数据返回给脚本时,实际锁状态可能已发生变化。

query()方法的步骤如下:

  1. environmentthis相关设置对象

  2. 如果environment相关全局对象关联 Document不是完全激活,则返回一个以"InvalidStateError"DOMException拒绝的 promise。

  3. manager获取锁管理器(参数为environment)的结果。如果返回失败,则返回一个以"SecurityError"DOMException拒绝的 promise。

  4. promise新建 promise

  5. 将以下步骤排队manager锁任务队列,以快照锁状态并传入promise

  6. 返回promise

3.3. Lock

[SecureContext, Exposed=(Window,Worker)]
interface Lock {
  readonly attribute DOMString name;
  readonly attribute LockMode mode;
};

Lock对象关联一个

name getter 的步骤是返回关联name

mode getter 的步骤是返回关联mode

4. 算法

4.1. 请求锁

请求锁,参数为promiseagentclientIdmanagercallbacknamemodeifAvailablestealsignal
  1. request为新建的锁请求agentclientIdmanagernamemodecallbackpromisesignal)。

  2. 如果signal存在,则添加算法signal to abort the request request(参数signal)到signal

  3. 将以下步骤排队锁任务队列

    1. queueMapmanager锁请求队列映射

    2. queue为从queueMap获取name对应的锁请求队列的结果。

    3. heldmanager已持有锁集合

    4. 如果steal为 true,则执行以下步骤:

      1. 遍历held中的每个lock

        1. 如果locknamename,则执行:

          1. 移除lockheld

          2. 拒绝lockreleased promise,错误为"AbortError"DOMException

      2. 前置requestqueue

    5. 否则,执行以下步骤:

      1. 如果ifAvailable为 true 且request不是grantable,则在callback相关设置对象负责事件循环排队以下步骤

        1. r调用callback,参数为null的结果。

        2. resolvepromiser,并终止这些步骤。

      2. 入队requestqueue

    6. 处理锁请求队列queue

  4. 返回request

4.2. 释放锁

释放锁lock
  1. 断言:这些步骤在锁任务队列上运行。

  2. managerlockmanager

  3. queueMapmanager锁请求队列映射

  4. namelock资源名

  5. queue为从queueMap获取name对应的锁请求队列的结果。

  6. 移除lockmanager已持有锁集合

  7. 处理锁请求队列queue

4.3. 中止请求

中止请求request
  1. 断言:这些步骤在锁任务队列上运行。

  2. managerrequestmanager

  3. namerequestname

  4. queueMapmanager锁请求队列映射

  5. queue为从queueMap获取name对应的锁请求队列的结果。

  6. 移除requestqueue

  7. 处理锁请求队列queue

signal to abort the requestrequest,参数signal
  1. 将以下步骤排队中止请求request锁任务队列

  2. 拒绝requestpromise,错误为signal中止原因

4.4. 处理指定资源名的锁请求队列

处理锁请求队列queue
  1. 断言:这些步骤在锁任务队列上运行。

  2. 遍历queue中的每个request

    1. 如果request不是grantable,则返回。

      注意:队列中只有第一个成员是 grantable。如果某项不可授予,则后续所有项也自动不可授予。

    2. 移除requestqueue

    3. agentrequestagent

    4. managerrequestmanager

    5. clientIdrequestclientId

    6. namerequestname

    7. moderequestmode

    8. callbackrequestcallback

    9. prequestpromise

    10. signalrequestsignal

    11. waiting新建 promise

    12. lock为新建的,参数为agentagentclientIdclientIdmanagermanagermodemodenamenamereleased promisepwaiting promisewaiting

    13. 追加lockmanager已持有锁集合

    14. 将以下步骤排队callback相关设置对象负责事件循环

      1. 如果signal存在,则执行:

        1. 如果signal中止,则执行:

          1. 将以下步骤排队锁任务队列

            1. 释放锁lock

          2. 返回。

        2. 移除算法signal to abort the requestrequestsignal

      2. r调用callback,参数为新建的、关联lockLock对象。

      3. resolvewaitingr

4.5. 锁状态快照

要为managerpromise快照锁状态
  1. 断言:这些步骤在锁任务队列上运行。

  2. pending为新建的列表

  3. 遍历manager锁请求队列映射所有值,即每个queue

    1. 遍历queue中的每个request

      1. 追加«[ "name" → requestname, "mode" → requestmode, "clientId" → requestclientId ]»到pending

  4. held为新建的列表

  5. 遍历manager已持有锁集合中的每个lock

    1. 追加«[ "name" → lockname, "mode" → lockmode, "clientId" → lockclientId ]»到held

  6. resolvepromise为«[ "held" → held, "pending" → pending ]»。

对于任意资源,pending 锁请求的快照会按请求发起顺序返回; 但不同资源间的请求顺序不保证。例如,若对资源 A 依次发起 A1、A2 请求,对资源 B 依次发起 B1、B2 请求,则«A1, A2, B1, B2»和«A1, B1, A2, B2»都可能作为快照的 pending 列表顺序。

已持有锁状态的快照不保证顺序。

5. 使用注意事项

本节为非规范性内容。

5.1. 死锁

死锁是并发计算中的一个概念,针对特定锁管理器的死锁可以通过本 API 引入。

通过本 API 可能遇到死锁的示例如下:

脚本 1:

navigator.locks.request('A', async a => {
  await navigator.locks.request('B', async b => {
    // do stuff with A and B
  });
});

脚本 2:

navigator.locks.request('B', async b => {
  await navigator.locks.request('A', async a => {
    // do stuff with A and B
  });
});

如果脚本 1 和脚本 2几乎同时运行,则可能出现脚本 1持有锁 A、脚本 2持有锁 B,且双方都无法继续——即死锁。这不会影响整个用户代理,不会暂停标签页,也不会影响同源的其他脚本,但此功能会被阻塞。

防止死锁需要谨慎。一个方法是始终按严格顺序获取多个锁。

如下辅助函数可用于按一致顺序请求多个锁:

async function requestMultiple(resources, callback) {
  const sortedResources = [...resources];
  sortedResources.sort(); // 始终按相同顺序请求。

  async function requestNext(locks) {
    return await navigator.locks.request(sortedResources.shift(), async lock => {
      // 当前持有此锁及之前所有已请求的锁。
      locks.push(lock);

      // 如有需要,递归请求下一个锁。
      if (sortedResources.length > 0)
        return await requestNext(locks);

      // 否则,执行回调。
      return await callback(locks);

      // 回调返回(或抛出)后,所有锁将被释放。
    });
  }
  return await requestNext([]);
}

实际使用中,多锁场景往往并不如此直接——库和工具常常会无意中掩盖锁的使用。

6. 安全与隐私注意事项

6.1. 锁作用域

锁管理器的作用域定义很重要,因为它决定了隐私边界。锁可作为临时状态保留机制,也可像存储 API 一样作为通信机制,其权限不得高于存储机制。用户代理如果对某项服务施加更细粒度的隔离,也必须对其他服务施加同样的隔离;例如,用户代理因隐私原因对同一源的顶级页面(第一方)和跨域 iframe(第三方)分别分区存储,则也必须对锁进行类似分区。

这也为 Web 应用作者提供了合理预期:如果对某存储资源获取了锁,则所有同源浏览上下文都必须观察到相同状态。

6.2. 隐私浏览

每个隐私模式浏览会话在本 API 中视为独立的用户代理。即,隐私模式外请求/持有的锁不会影响隐私模式内的锁,反之亦然。这既防止网站判断会话是否为“隐身”,也不允许不同会话间通信。

6.3. 实现风险

实现必须确保锁不会跨源。否则会为不同源脚本间通信提供侧信道,或允许一个源的脚本干扰另一个源的行为(如拒绝服务)。

6.4. 安全与隐私清单

W3C TAG 制定了安全与隐私自查问卷,供规范编辑者参考。相关问题如下:

7. 致谢

特别感谢 Alex Russell, Andreas Butler, Anne van Kesteren, Boris Zbarsky, Chris Messina, Darin Fisher, Domenic Denicola, Gus Caplan, Harald Alvestrand, Jake Archibald, Kagami Sascha Rosylight, L. David Baron, Luciano Pacheco, Marcos Caceres, Ralph Chelala, Raymond Toy, Ryan Fioravanti, 以及 Victor Costan 对本提案的贡献。

特别感谢 Tab Atkins, Jr. 创建和维护 Bikeshed,本规范所用的文档工具,以及他在文档编写方面的建议。

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语结合表达。 本规范规范性部分中的关键词 “MUST”、 “MUST NOT”、 “REQUIRED”、 “SHALL”、 “SHALL NOT”、 “SHOULD”、 “SHOULD NOT”、 “RECOMMENDED”、 “MAY”、 “OPTIONAL” 按 RFC 2119 的定义解释。 但为便于阅读,这些词在本规范中不会全部大写。

除明确标记为非规范性、示例和注释的部分外,本规范所有文本均为规范性内容。[RFC2119]

本规范中的示例以 “for example” 开头,或通过 class="example" 与规范性文本区分,如下所示:

这是一个说明性示例。

说明性注释以 “Note” 开头,并通过 class="note" 与规范性文本区分,如下所示:

注意,这是一个说明性注释。

一致性算法

作为算法一部分的命令式要求(如 “strip any leading space characters” 或 “return false and abort these steps”) 应结合引入算法时所用关键词(“must”、“should”、“may”等)来解释其含义。

以算法或具体步骤表述的一致性要求可用任何方式实现,只要最终结果等价即可。 本规范定义的算法旨在易于理解,并非为高性能设计。鼓励实现者进行优化。

索引

本规范定义的术语

引用规范定义的术语

参考文献

规范性引用

[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; 等. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFCs 中用于指示需求级别的关键词. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[Storage]
Anne van Kesteren. 存储标准. 现行标准. URL: https://storage.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

说明性引用

[IndexedDB-2]
Ali Alabbas; Joshua Bell. Indexed Database API 2.0. 2018年1月30日. REC. URL: https://www.w3.org/TR/IndexedDB-2/
[Service-Workers]
Yoshisato Yanagisawa; Monica CHINTALA. Service Workers. 2025年3月6日. CRD. URL: https://www.w3.org/TR/service-workers/

IDL 索引

[SecureContext]
interface mixin NavigatorLocks {
  readonly attribute LockManager locks;
};
Navigator includes NavigatorLocks;
WorkerNavigator includes NavigatorLocks;

[SecureContext, Exposed=(Window,Worker)]
interface LockManager {
  Promise<any> request(DOMString name,
                       LockGrantedCallback callback);
  Promise<any> request(DOMString name,
                       LockOptions options,
                       LockGrantedCallback callback);

  Promise<LockManagerSnapshot> query();
};

callback LockGrantedCallback = Promise<any> (Lock? lock);

enum LockMode { "shared", "exclusive" };

dictionary LockOptions {
  LockMode mode = "exclusive";
  boolean ifAvailable = false;
  boolean steal = false;
  AbortSignal signal;
};

dictionary LockManagerSnapshot {
  sequence<LockInfo> held;
  sequence<LockInfo> pending;
};

dictionary LockInfo {
  DOMString name;
  LockMode mode;
  DOMString clientId;
};

[SecureContext, Exposed=(Window,Worker)]
interface Lock {
  readonly attribute DOMString name;
  readonly attribute LockMode mode;
};

问题索引

需完善与 [Storage] 的集成,包括如何从给定环境正确获取锁管理器。
当前仅适用于 worker,且定义不够明确,因为没有规范性方法在 worker 终止时运行相关步骤。
MDN

Lock/mode

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Lock/name

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Lock

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

LockManager/query

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

LockManager/request

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

LockManager

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Navigator/locks

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

WorkerNavigator/locks

In all current engines.

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?