Web 锁 API

W3C 首次公开工作草案,

有关此文档的更多详细信息
此版本:
https://www.w3.org/TR/2023/WD-web-locks-20230105/
最新发布的版本:
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
规范内的行内问题
编辑:
(Google Inc.)
(Mozilla)

摘要

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

本文件的状态

此部分描述了该文档在发布时的状态。当前W3C出版物列表及本技术报告的最新修订版可在W3C技术报告索引(https://www.w3.org/TR/)中找到。

本文档由Web 应用工作组发布为工作草案。此文档旨在成为 W3C 推荐标准。

本文档由Web 应用工作组作为首次公开工作草案发布,使用 推荐轨道。 欢迎对本规范的反馈和评论。请使用 GitHub 问题进行反馈。历史讨论可在public-webapps@w3.org 存档中找到。

作为首次公开工作草案发布并不意味着获得 W3C及其成员的认可。这是一个草案文档,可能会随时更新、替换或废弃。在其他情况下引用该文档是不合适的,除非作为工作进展。

本文档由依据 W3C 专利政策运营的团体制作。W3C 维护了一份与该团体的交付物有关的专利披露的公开列表;该页面还包括有关披露专利的说明。个人如果已知包含 必要权利要求的专利,必须根据 W3C 专利政策第6条披露信息。

本文档受 2021年11月2日 W3C 流程文档管理。

1. 介绍

本节是非规范性的。

脚本对特定的锁请求发起操作, 请求特定的资源名称模式。调度算法查看当前和之前请求的状态, 最终授予锁请求。是一个已授予的请求; 它有一个资源名称模式。它作为一个返回给脚本的对象表示。 只要锁被持有,它可能阻止其他锁请求被授予(取决于名称和模式)。脚本可以释放锁, 此时它可能允许其他锁请求被授予。

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

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

1.1. 使用概述

该 API 的使用步骤如下:

  1. 请求锁。

  2. 在异步任务中持有锁时执行工作。

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

1.2. 动机和使用案例

基于 Web 的文档编辑器将状态存储在内存中以便快速访问,并将更改(作为一系列记录)持久化到存储 API, 例如 Indexed Database API, 以提高弹性和离线使用能力,同时同步到服务器以支持跨设备使用。当同一文档在两个标签页中打开进行编辑时,必须在这些标签页之间进行协调, 例如确保一次只能有一个标签页对文档进行修改或同步。需要在活动标签页离开(导航、关闭、崩溃)时使其他标签页可以变为活动状态。

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

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

2. 概念

本规范的目的如下:

一个用户代理具有一个 锁任务队列,它是 启动新的并行队列的结果。

任务来源对于下面排队的步骤Web 锁任务来源

2.1. 资源名称

资源名称是由 web 应用程序选择的表示抽象资源的 JavaScript 字符串

资源名称在调度算法之外没有外部含义,但在共享 代理存储桶中是全局的。 Web 应用程序可以自由使用任何资源命名方案。

以 U+002D HYPHEN-MINUS(-)开头的资源名称是保留的;请求这些资源名称将引发异常。

2.2. 锁管理器

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

注意:页面和 worker(代理) 共享一个存储桶, 即使它们处于不相关的浏览上下文中, 但它们仍共享同一个锁管理器

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

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

  3. bottlemap相关联的 存储瓶

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

这里需要完善与 [存储]的集成, 包括如何从给定环境中正确获取锁管理器。

2.3. 模式和调度

模式可以是 "exclusive" 或 "shared"。 模式可以用于模拟常见的 读写锁模式。 如果持有 "exclusive" 锁, 则无法授予该名称的其他锁。如果持有 "shared" 锁, 则可以授予其他具有相同名称的 "shared" 锁, 但不能授予任何 "exclusive" 锁。 API 中的默认模式是 "exclusive"。

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

2.4.

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

一个具有一个代理,它是一个 代理

一个具有一个clientId,它是一个不透明的字符串。

一个具有一个管理器,它是一个锁管理器

一个具有一个名称,它是一个资源名称

一个具有一个模式,它是"exclusive" 或 "shared"中的一个。

一个具有一个等待的 promise,它是一个 Promise。

一个具有一个释放的 promise,它是一个 Promise。

每个锁管理器具有一个持有的锁集合, 它是锁的有序集合

lock等待的 promise 完成(成功或失败)时,排队以下步骤锁任务队列中:

  1. 释放锁 lock

  2. 解决 lock释放的 promise, 使用lock等待的 promise

2.5. 锁请求

锁请求表示一个待处理的请求。

一个锁请求是一个结构体, 具有以下代理clientId管理器名称模式回调函数promise,以及信号

锁请求队列 是一个队列,其中包含锁请求

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

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

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

  2. 返回queueMap[name]。

当以下步骤返回 true 时,表示锁请求 request可授予的

  1. managerrequest管理器

  2. queueMapmanager锁请求队列映射

  3. namerequest名称

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

  5. heldmanager持有的锁集合

  6. moderequest模式

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

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

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

2.6. 锁的终止

每当运行卸载文档清理步骤时,对其文档使用终止剩余锁和请求的过程,其对应的代理

代理终止时,终止剩余锁和请求

目前这仅适用于工作线程,并且定义得较为模糊,因为没有规范的方法来在工作线程终止时运行步骤。

为了终止剩余锁和请求,使用代理,在锁任务队列中排入以下步骤

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

    1. 中止请求 request

  2. 对于每个 lock,其代理等于代理

    1. 释放锁 lock

3. API

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

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

Navigator/locks

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?

locks 获取器的步骤是返回 此对象相关设置对象LockManager 对象。

3.2. LockManager

LockManager

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?
[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()

LockManager/request

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?
promise = navigator.locks.request(name, callback)
promise = navigator.locks.request(name, options, callback)

调用 request() 方法来请求一个锁。

name(初始参数)是一个 资源名称字符串。

callback(最后一个参数)是一个当锁被授予时调用的 回调函数。这是由脚本指定的,通常是一个 async 函数。锁在回调函数完成之前一直被持有。如果传递了一个非异步的回调函数,它将自动包裹在一个立即解析的 Promise 中,因此锁只会在同步回调的持续时间内持有。

返回的 promise 在锁释放后解析(或拒绝)回调的结果,如果请求被中止则拒绝。

示例:

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"。多个标签页或工作者可以以 "shared" 模式持有对同一资源的锁,但在 "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| 将是一个名称为 "AbortError" 的 DOMException。
}

如果在授予锁之前发出中止信号,则请求的 Promise 将以 AbortError 被拒绝。一旦锁被授予,信号将被忽略。

options.steal

如果 steal 选项为 true,则将释放对该资源持有的任何锁(并且此类锁的 释放的 Promise 将以 AbortError 解析),并授予请求,抢占任何排队的请求。

如果 Web 应用程序检测到不可恢复的状态 — 例如,一些协调点(如 Service Worker)确定持有锁的标签页不再响应 — 那么可以使用此选项 "窃取" 锁。

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

  1. 如果没有传递 options,则让 options 为一个新的 LockOptions 字典,其成员使用默认值。

  2. environmentthis相关设置对象

  3. 如果 environment相关全局对象关联的文档 不是 完全激活的,则返回 一个被拒绝的 Promise,带有一个 "InvalidStateError" DOMException

  4. manager获取锁管理器 的结果,给定 environment。如果返回失败,则返回 一个被拒绝的 Promise,带有一个 "SecurityError" DOMException

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

  6. 如果 options["steal"] 和 options["ifAvailable"] 都为 true,则返回 一个被拒绝的 Promise,带有一个 "NotSupportedError" DOMException

  7. 如果 options["steal"] 为 true 且 options["mode"] 不是 "exclusive",则返回 一个被拒绝的 Promise,带有一个 "NotSupportedError" DOMException

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

  9. 如果 options["signal"] 存在 且已 中止,则返回 一个被拒绝的 Promise,包含 options["signal"] 的 中止原因

  10. promise一个新的 Promise

  11. 请求一个锁,传入 promise、当前的 代理environmentidmanagercallbacknameoptions["mode"]、options["ifAvailable"]、options["steal"] 和 options["signal"]。

  12. 返回 promise

3.2.2. 方法 query()

LockManager/query

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?
state = await navigator.locks.query()

可以使用 query() 方法为一个源生成 锁管理器状态的快照,这允许 Web 应用程序检查其锁的使用情况,用于日志记录或调试目的。

返回的 Promise 解析为 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 字段对应于唯一的上下文(框架或工作者),并且是 Clientid 属性返回的相同值。

方法 query() 的步骤如下:

  1. environmentthis相关设置对象

  2. 如果 environment相关全局对象关联的文档 不是 完全激活的,则返回 一个被拒绝的 Promise,带有一个 "InvalidStateError" DOMException

  3. manager获取锁管理器 的结果,给定 environment。如果返回失败,则返回 一个被拒绝的 Promise,带有一个 "SecurityError" DOMException

  4. promise一个新的 Promise

  5. 将步骤排入队列快照锁状态,传入 managerpromise锁任务队列

  6. 返回 promise

3.3. Lock

Lock

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?
[SecureContext, Exposed=(Window,Worker)]
interface Lock {
  readonly attribute DOMString name;
  readonly attribute LockMode mode;
};

Lock 对象有一个关联的

Lock/name

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?

name 获取器的步骤是返回关联的 名称

Lock/mode

在所有当前的引擎中可用。

Firefox96+Safari15.4+Chrome69+
Opera?Edge79+
Edge (旧版)?IE
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?三星 Internet?Opera Mobile?

mode 获取器的步骤是返回关联的 模式

4. 算法

4.1. 请求锁

请求锁,需使用 promiseagentclientIdmanagercallbacknamemodeifAvailablestealsignal
  1. request 成为一个新的 锁请求 (agentclientIdmanagernamemodecallbackpromisesignal)。

  2. 如果存在 signal,则将算法 信号中止请求 request 使用 signal 添加到 signal 中。

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

    1. queueMapmanager锁请求队列映射

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

    3. heldmanager持有锁集合

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

      1. 对于每个 lock 属于 held

        1. 如果 lock名称name,则运行以下步骤:

          1. held移除锁 lock

          2. 拒绝 lock释放承诺,错误为 "AbortError" DOMException

      2. request 前置到 queue 中。

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

      1. 如果 ifAvailable 为 true 且 request 不可 授予,则将以下步骤排入队列,在 callback相关设置对象负责事件循环中执行:

        1. r 成为调用 callback,并将 null 作为唯一参数的结果。

        2. 解决 promise 使用 r,并终止这些步骤。

      2. request 入列到 queue 中。

    6. 处理锁请求队列 queue

  4. 返回 request

4.2. 释放锁

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

  2. managerlock管理器

  3. queueMapmanager锁请求队列映射

  4. namelock资源名称

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

  6. manager持有锁集合中移除 lock

  7. 处理锁请求队列 queue

4.3. 中止请求

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

  2. managerrequest管理器

  3. namerequest名称

  4. queueMapmanager锁请求队列映射

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

  6. queue 中移除 request

  7. 处理锁请求队列 queue

发送信号中止请求 request,使用 signal
  1. 将步骤排入队列,将 中止请求 request 添加到 锁任务队列 中。

  2. 拒绝 request承诺,使用 signal中止原因

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

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

  2. queue 中的每个 request

    1. 如果 request 不是 可授予的,则返回。

      注意:队列中只有第一个项目是可授予的。因此,如果某个项目不可授予,那么后面的所有项目也自动不可授予。

    2. queue 中移除 request

    3. agentrequest代理

    4. managerrequest管理器

    5. clientIdrequest客户端ID

    6. namerequest名称

    7. moderequest模式

    8. callbackrequest回调函数

    9. prequest承诺

    10. signalrequest信号

    11. waiting一个新的承诺

    12. lock 成为一个新的 ,具有 代理 agent客户端ID clientId管理器 manager模式 mode名称 name释放承诺 p,以及 等待承诺 waiting

    13. 追加 lockmanager持有锁集合

    14. 将以下步骤排入队列,在 callback相关设置对象负责事件循环中:

      1. 如果 signal 存在,则运行以下步骤:

        1. 如果 signal中止,则运行以下步骤:

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

            1. 释放锁 lock

          2. 返回。

        2. 移除算法 信号以中止请求 request,从 signal 中。

      2. r 为通过 调用 callback,并以与 lock 相关联的新 Lock 对象作为唯一参数的结果。

      3. 解决 waiting,值为 r

4.5. 快照锁状态

manager 生成锁状态的快照,使用 promise
  1. 断言:这些步骤在 锁任务队列中执行。

  2. pending 为一个新的 列表

  3. manager锁请求队列映射中的每个 queue

    1. queue 中的每个 request

      1. «[ "name" → request名称,"mode" → request模式,"clientId" → request客户端ID ]» 添加到 pending

  4. held 为一个新的 列表

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

    1. «[ "name" → lock名称,"mode" → lock模式,"clientId" → lock客户端ID ]» 添加到 held

  6. 解决 promise,值为 «[ "held" → held,"pending" → pending ]»。

5. 使用注意事项

本节为非规范性内容。

5.1. 死锁

死锁是并发计算中的一个概念,通过此 API 可以引入限制在特定 锁管理器的死锁。

防止死锁需要小心。一种方法是始终按照严格的顺序获取多个锁。

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]

本规范中的示例由“例如”一词引入,或与规范性文本分开,使用 class="example" 进行标记,如下所示:

这是一个信息性示例。

信息性注释以“注意”一词开头,并与规范性文本分开,使用 class="note" 进行标记,如下所示:

注意,这是一个信息性注释。

一致性算法

在算法部分以命令形式表述的要求(如“去除所有前导空格字符”或“返回 false 并中止这些步骤”),应根据引入该算法时使用的关键词(如“必须”、“应当”、“可以”等)来解释其含义。

以算法或特定步骤形式表述的一致性要求可以通过任何方式实现,只要最终结果是等效的即可。特别是,本规范中定义的算法旨在易于理解,而非旨在高效实现。建议实现者进行优化。

索引

本规范定义的术语

通过引用定义的术语

参考文献

规范性参考文献

[CSS21]
Bert Bos 等人。层叠样式表 2.1 版 (CSS 2.1) 规范。2011年6月7日。REC。URL: https://www.w3.org/TR/CSS21/
[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。用于在RFC中表示需求级别的关键字。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。索引数据库 API 2.0。2018年1月30日。REC。URL: https://www.w3.org/TR/IndexedDB-2/
[Service-Workers]
Jake Archibald; Marijn Kruisselbrink。Service Workers。2022年7月12日。CR。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] 的集成,包括如何从给定的环境中正确获取锁管理器。
目前这仅适用于工作者,并且定义不明确,因为没有规范的方法来在工作者终止时执行步骤。