Indexed Database API 2.0 (索引数据库 API 2.0)

W3C 推荐标准,

此版本
https://w3org.cn/TR/2018/REC-IndexedDB-2-20180130/
最新发布版本
https://w3org.cn/TR/IndexedDB-2/
编辑草案
https://w3c.github.io/IndexedDB/
历史版本
测试套件
https://github.com/w3c/web-platform-tests/tree/master/IndexedDB
问题追踪
GitHub
编辑
(微软公司)
(谷歌公司)

本文档的勘误表记录在 GitHub 问题中。

本规范的英文版本是唯一规范版本。非规范的翻译版本或许也可提供。


摘要

本文档定义了一套数据库 API,用于存储包含简单值和层级对象的记录。每条记录由一个键和一个值组成。此外,数据库还维护其存储记录的索引。应用开发者可以直接使用 API 通过键或索引来定位记录。可以在此 API 之上构建查询语言。索引数据库可以使用持久化的 B 树数据结构来实现。

关于本文档

本节描述了本文件发布时的状态。其他文件可能会取代本文件。W3C 当前出版物列表和本技术报告的最新修订版本可在 https://w3org.cn/TR/ 的 W3C 技术报告索引中找到。

这是 Indexed Database API 的第二版。第一版于 2015 年 1 月 8 日成为 W3C 推荐标准。

引用自 [CSS-CASCADE-4][DOM41] 的概念已经长期稳定,预计在这些规范向 W3C 推荐标准推进的过程中不会发生改变。

本文档由 Web 平台工作组作为 W3C 推荐标准发布。

邀请 W3C 会员及其他相关方审阅本文档,并将意见发送至 public-webapps@w3.org (订阅, 存档),或在 GitHub 上提交错误报告

请参阅工作组的实现报告

本文档已由 W3C 会员、软件开发人员以及其他 W3C 小组和利益相关方审阅,并由理事长批准为 W3C 推荐标准。这是一份稳定的文档,可用作参考材料或在其他文档中引用。W3C 制定推荐标准的目的是引起对该规范的关注并促进其广泛部署。这增强了 Web 的功能和互操作性。

本文档由在一个受 W3C 专利政策约束的小组下运作的团体制作。W3C 维护一份与该组交付成果相关的专利披露公开列表;该页面还包含了披露专利的说明。任何个人如果确实知晓某个其认为包含必要权利要求的专利,必须根据 W3C 专利政策第 6 节披露该信息。

本文档受 2017 年 3 月 1 日版 W3C 流程文档管辖。

1. 引言

用户代理需要在本地存储大量对象,以满足 Web 应用的离线数据需求。[WEBSTORAGE] 对于存储键值对很有用。但是,它不提供键的顺序检索、值的高效搜索,也不支持为同一个键存储多个重复值。

本规范提供了一个具体的 API 来执行高级键值数据管理,这是大多数复杂查询处理器的核心。它通过使用事务性数据库来存储键及其对应的值(每个键可以有一个或多个),并提供了一种以确定性顺序遍历键的方法。这通常通过使用持久化的 B 树数据结构来实现,该结构在插入、删除以及对大量数据记录进行顺序遍历方面被认为是高效的。

2. 构造

名称是一个等同于 DOMString 的字符串;即任意长度的 16 位代码单元的任意序列,包括空字符串。名称总是作为不透明的 16 位代码单元序列进行比较。

排序名称列表是一个包含按 16 位代码单元升序排序的名称的列表。

详细信息

这与对数组 字符串执行的 Array.prototype.sort 相匹配。此排序顺序比较每个字符串中的 16 位代码单元,产生一种高效、一致且确定的排序顺序。生成的列表将不会匹配任何特定的字母表或字典顺序,特别是对于由代理对表示的代码点。

2.1. 数据库

每个都有一个关联的数据库集合。数据库拥有零个或多个保存数据库中存储数据的对象存储

数据库有一个名称,用于在特定内标识它。该名称是一个名称,在数据库的生命周期内保持不变。

数据库有一个版本。当数据库首次创建时,其版本为 0(零)。

数据库最多有一个关联的升级事务,其值为 null 或一个升级事务,初始为 null。

2.1.1. 数据库连接

脚本不会直接与数据库交互。相反,脚本通过连接进行间接访问。连接对象可用于操作该数据库的对象。这也是获取该数据库事务的唯一方式。

打开数据库的操作会创建一个连接。在任何给定时间,可能存在对给定数据库的多个连接

连接只能访问与从中打开连接的全局作用域的相关联的数据库

连接有一个版本,在连接创建时设置。除非升级被终止,否则它在连接的生命周期内保持不变,在这种情况下它会被设置为数据库的前一个版本。一旦连接关闭,版本就不会改变。

每个连接都有一个关闭挂起标志,初始为未设置。

连接最初创建时,它处于已打开状态。连接可以通过多种方式关闭。如果创建连接的执行上下文被销毁(例如由于用户导航离开该页面),则连接关闭。连接也可以使用关闭数据库连接的步骤显式关闭。当连接关闭时,如果关闭挂起标志尚未设置,则始终会将其设置为已设置。

连接可能会在特殊情况下被用户代理关闭,例如由于无法访问文件系统、权限更改或清除源的存储。如果发生这种情况,用户代理必须运行带有连接并设置了 强制标志关闭数据库连接步骤。

连接有一个对象存储集,在连接创建时,它被初始化为关联数据库中的对象存储集合。除非运行升级事务,否则该集合的内容保持不变。

连接获取父级算法返回 null。

如果尝试升级或删除数据库,则会向打开的连接触发版本变更事件。这使连接有机会关闭,以允许升级或删除继续进行。

2.2. 对象存储

对象存储是用于在数据库中存储数据的主要存储机制。

每个数据库都有一组对象存储对象存储集可以更改,但只能使用升级事务,即响应 upgradeneeded 事件时。当创建一个新数据库时,它不包含任何对象存储

对象存储有一个记录列表,用于保存存储在对象存储中的数据。每条记录由一个和一个组成。列表根据键按升序进行排序。在给定的对象存储中,永远不能有多个具有相同键的记录。

对象存储有一个名称,是一个名称。在任何时候,该名称在其所属的数据库中都是唯一的。

对象存储可选地具有一个键路径。如果对象存储具有键路径,则称其使用内联键。否则,称其使用离线键

对象存储可选地具有一个键生成器

对象存储可以通过以下三种来源之一为记录推导

  1. 一个键生成器。每当需要键时,键生成器都会生成一个单调递增的数字。

  2. 键可以通过键路径推导。

  3. 存储在对象存储中时,也可以显式指定键。

2.2.1. 对象存储句柄

脚本不会直接与对象存储交互。相反,在事务内,脚本通过对象存储句柄进行间接访问。

对象存储句柄有一个关联的对象存储和一个关联的事务。多个句柄可以与不同事务中的同一个对象存储相关联,但在一个事务内,必须只有一个与特定对象存储相关联的对象存储句柄

对象存储句柄有一个索引集,在对象存储句柄创建时,它被初始化为引用关联对象存储索引集合。除非运行升级事务,否则该集合的内容保持不变。

对象存储句柄有一个名称,在对象存储句柄创建时被初始化为关联对象存储名称。除非运行升级事务,否则该名称保持不变。

2.3.

每条记录都与一个相关联。用户代理必须支持任何可序列化对象。这包括简单类型(如字符串基本值和Date对象)以及ObjectArray实例、File对象、Blob对象、ImageData对象等。记录按值存储和检索,而不是按引用;后续对值的更改对存储在数据库中的记录没有影响。

记录StructuredSerializeForStorage 操作输出的记录

2.4.

为了高效检索存储在索引数据库中的记录,每条记录都根据其进行组织。

有一个关联的类型,为以下之一:数字日期字符串二进制数组

还有一个关联的,它将是:如果类型是 数字日期,则为 unrestricted double;如果类型是 字符串,则为 DOMString;如果类型是 二进制,则为 octet 列表;如果类型是 数组,则为其他的列表。

ECMAScript [ECMA-262] 值可以通过遵循将值转换为键的步骤转换为

数组键是一个类型为 数组数组键子键数组键列表的成员。

比较两个键 ab,请运行以下步骤:

  1. taa类型

  2. tbb类型

  3. 如果 ta数组tb二进制字符串日期数字,则返回 1。

  4. 如果 tb数组ta二进制字符串日期数字,则返回 -1。

  5. 如果 ta二进制tb字符串日期数字,则返回 1。

  6. 如果 tb二进制ta字符串日期数字,则返回 -1。

  7. 如果 ta字符串tb日期数字,则返回 1。

  8. 如果 tb字符串ta日期数字,则返回 -1。

  9. 如果 ta日期tb数字,则返回 1。

  10. 如果 tb日期ta数字,则返回 -1。

  11. 断言:tatb 相等。

  12. vaa

  13. vbb

  14. 切换 ta

    number
    日期
    1. 如果 va 大于 vb,则返回 1。

    2. 如果 va 小于 vb,则返回 -1。

    3. 返回 0。

    string
    1. lengthva 的长度和 vb 的长度中的较小者。

    2. i 为 0。

    3. i 小于 length 时:

      1. uva 在索引 i 处的代码单元。

      2. vvb 在索引 i 处的代码单元。

      3. 如果 u 大于 v,则返回 1。

      4. 如果 u 小于 v,则返回 -1。

      5. i 增加 1。

    4. 如果 va 的长度大于 vb 的长度,则返回 1。

    5. 如果 va 的长度小于 vb 的长度,则返回 -1。

    6. 返回 0。

    二进制:
    1. lengthva 的长度和 vb 的长度中的较小者。

    2. i 为 0。

    3. i 小于 length 时:

      1. uva 中索引 i 处的 octet

      2. vvb 中索引 i 处的 octet

      3. 如果 u 大于 v,则返回 1。

      4. 如果 u 小于 v,则返回 -1。

      5. i 增加 1。

    4. 如果 va 的长度大于 vb 的长度,则返回 1。

    5. 如果 va 的长度小于 vb 的长度,则返回 -1。

    6. 返回 0。

    array
    1. lengthva 的长度和 vb 的长度中的较小者。

    2. i 为 0。

    3. i 小于 length 时:

      1. uva 中索引 i 处的

      2. vvb 中索引 i 处的

      3. c 为递归运行比较两个键步骤的结果,参数为 uv

      4. 如果 c 不为 0,则返回 c

      5. i 增加 1。

    4. 如果 va 的长度大于 vb 的长度,则返回 1。

    5. 如果 va 的长度小于 vb 的长度,则返回 -1。

    6. 返回 0。

如果运行比较两个键步骤的结果为 1,则 a 大于 b

如果运行比较两个键步骤的结果为 -1,则 a 小于 b

如果运行比较两个键步骤的结果为 0,则 a 等于 b

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语相结合来表达。本文档规范性部分中的关键词“MUST”(必须)、“MUST NOT”(不得)、“REQUIRED”(必需)、“SHALL”(应)、“SHALL NOT”(不应)、“SHOULD”(推荐)、“SHOULD NOT”(不推荐)、“RECOMMENDED”(建议)、“MAY”(可以)和“OPTIONAL”(可选)应按照 RFC 2119 中的描述进行解释。然而,为了可读性,这些词在本文档中不以全大写形式出现。

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

本规范中的示例均以“例如”一词引入,或者通过 class="example" 与规范性文本隔开,如下所示

这是一个说明性示例。

说明性注释以“Note”一词开头,并使用 class="note" 与规范性文本隔开,如下所示

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

符合要求的算法

作为算法一部分的祈使语气要求(例如“去除任何前导空格字符”或“返回 false 并中止这些步骤”)应根据引入算法时使用的关键词(“必须”、“应该”、“可以”等)进行解释。

只要最终结果 等效,以算法或特定步骤表述的合规性要求可以以任何方式实现。特别是,本规范中定义的算法旨在易于理解,而不旨在达到最高性能。鼓励实现者进行优化。

.

索引

本规范定义的术语

通过引用定义的术语

引用

规范性引用

[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. 14 January 2016. CR. URL: https://w3org.cn/TR/css-cascade-4/
[DOM41]
Yongsheng Zhu. DOM 4.1. WD. URL: https://w3org.cn/TR/dom41/
[ECMA-262]
ECMAScript 语言规范. URL: https://tc39.github.io/ecma262/
[FileAPI]
Marijn Kruisselbrink. File API. 2017年10月26日. WD. URL: https://w3org.cn/TR/FileAPI/
[HTML52]
HTML 5.2. Steve Faulkner; Arron Eicholz; Travis Leithead; Alex Danilo; Sangwhan Moon. W3C. 2017年12月14日. W3C Recommendation. URL: https://w3org.cn/TR/html52/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准。现行标准。网址:https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFC 中用于指示需求级别的关键词. 1997 年 3 月. 最佳当前实践. URL: https://tools.ietf.org/html/rfc2119
[WEBIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. URL: https://w3org.cn/TR/WebIDL-1/

参考资料

[Charmod-Norm]
Addison Phillips; et al. 万维网字符模型:字符串匹配与搜索. 2016年4月7日. WD. URL: https://w3org.cn/TR/charmod-norm/
[COOKIES]
A. Barth. HTTP 状态管理机制. 2011年4月. 提议标准. URL: https://tools.ietf.org/html/rfc6265
[WEBSTORAGE]
Ian Hickson. Web Storage (第二版). 2016年4月19日. REC. URL: https://w3org.cn/TR/webstorage/

IDL 索引

[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonly attribute any result;
  readonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // Event handlers:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending",
  "done"
};

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};

[Exposed=(Window,Worker),
 Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
interface IDBVersionChangeEvent : Event {
  readonly attribute unsigned long long oldVersion;
  readonly attribute unsigned long long? newVersion;
};

dictionary IDBVersionChangeEventInit : EventInit {
  unsigned long long oldVersion = 0;
  unsigned long long? newVersion = null;
};

partial interface WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};

[Exposed=(Window,Worker)]
interface IDBFactory {
  [NewObject] IDBOpenDBRequest open(DOMString name,
                                    optional [EnforceRange] unsigned long long version);
  [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);

  short cmp(any first, any second);
};

[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
  readonly attribute DOMString name;
  readonly attribute unsigned long long version;
  readonly attribute DOMStringList objectStoreNames;

  [NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
                                         optional IDBTransactionMode mode = "readonly");
  void close();

  [NewObject] IDBObjectStore createObjectStore(DOMString name,
                                               optional IDBObjectStoreParameters options);
  void deleteObjectStore(DOMString name);

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler onclose;
  attribute EventHandler onerror;
  attribute EventHandler onversionchange;
};

dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};

[Exposed=(Window,Worker)]
interface IDBObjectStore {
  attribute DOMString name;
  readonly attribute any keyPath;
  readonly attribute DOMStringList indexNames;
  [SameObject] readonly attribute IDBTransaction transaction;
  readonly attribute boolean autoIncrement;

  [NewObject] IDBRequest put(any value, optional any key);
  [NewObject] IDBRequest add(any value, optional any key);
  [NewObject] IDBRequest delete(any query);
  [NewObject] IDBRequest clear();
  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");

  IDBIndex index(DOMString name);

  [NewObject] IDBIndex createIndex(DOMString name,
                                   (DOMString or sequence<DOMString>) keyPath,
                                   optional IDBIndexParameters options);
  void deleteIndex(DOMString name);
};

dictionary IDBIndexParameters {
  boolean unique = false;
  boolean multiEntry = false;
};

[Exposed=(Window,Worker)]
interface IDBIndex {
  attribute DOMString name;
  [SameObject] readonly attribute IDBObjectStore objectStore;
  readonly attribute any keyPath;
  readonly attribute boolean multiEntry;
  readonly attribute boolean unique;

  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");
};

[Exposed=(Window,Worker)]
interface IDBKeyRange {
  readonly attribute any lower;
  readonly attribute any upper;
  readonly attribute boolean lowerOpen;
  readonly attribute boolean upperOpen;

  // Static construction methods:
  [NewObject] static IDBKeyRange only(any value);
  [NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false);
  [NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false);
  [NewObject] static IDBKeyRange bound(any lower,
                                       any upper,
                                       optional boolean lowerOpen = false,
                                       optional boolean upperOpen = false);

  boolean _includes(any key);
};

[Exposed=(Window,Worker)]
interface IDBCursor {
  readonly attribute (IDBObjectStore or IDBIndex) source;
  readonly attribute IDBCursorDirection direction;
  readonly attribute any key;
  readonly attribute any primaryKey;

  void advance([EnforceRange] unsigned long count);
  void continue(optional any key);
  void continuePrimaryKey(any key, any primaryKey);

  [NewObject] IDBRequest update(any value);
  [NewObject] IDBRequest delete();
};

enum IDBCursorDirection {
  "next",
  "nextunique",
  "prev",
  "prevunique"
};

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};

[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
  readonly attribute DOMStringList objectStoreNames;
  readonly attribute IDBTransactionMode mode;
  [SameObject] readonly attribute IDBDatabase db;
  readonly attribute DOMException error;

  IDBObjectStore objectStore(DOMString name);
  void abort();

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler oncomplete;
  attribute EventHandler onerror;
};

enum IDBTransactionMode {
  "readonly",
  "readwrite",
  "versionchange"
};