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

W3C 工作草案,

关于此文档的更多细节
此版本
https://w3org.cn/TR/2025/WD-IndexedDB-3-20250813/
最新发布版本
https://w3org.cn/TR/IndexedDB/
编辑草案
https://w3c.github.io/IndexedDB/
历史版本
历史
https://w3org.cn/standards/history/IndexedDB-3/
测试套件
https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
反馈
GitHub
编辑
(Microsoft)
前任编辑
Ali Alabbas (曾就职于 Microsoft)
Joshua Bell (曾就职于 Google)

摘要

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

关于本文档

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

本文档由 Web 应用工作组 作为工作草案,采用 推荐标准流程 发布。以工作草案形式发布并不意味着 W3C 及其成员的认可。

这是一个草案文档,可能随时会被其他文档更新、替换或废弃。将其作为进展中的工作之外的任何内容进行引用是不恰当的。

本文档由在 W3C 专利政策 下运作的小组编写。W3C 维护了一份 与该小组交付成果相关的专利披露公开列表;该页面还包括披露专利的指南。任何对个人认为包含 必要权利要求 的专利拥有实际知识的个人,必须根据 W3C 专利政策第 6 节 披露该信息。

本文档受 2023 年 11 月 3 日版 W3C 流程文档管辖。

这是 Indexed Database API 的第三版。第一版简称为“Indexed Database API”,于 2015 年 1 月 8 日成为 W3C 推荐标准。第二版标题为“Indexed Database API 2.0”,于 2018 年 1 月 30 日成为 W3C 推荐标准。

Indexed Database API 3.0 旨在取代 Indexed Database API 2.0。

1. 引言

用户代理需要在本地存储大量对象,以满足 Web 应用的离线数据需求。[WEBSTORAGE] 对于存储键值对非常有用。然而,它不支持键的有序检索、值的有效搜索,或同一个键存储多个重复值。

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

以下示例使用 API 访问名为 "library" 的数据库。它拥有一个 "books" 对象仓库,用于按 "isbn" 属性(作为主键)存储书籍记录。

书籍记录具有 "title" 属性。本示例人为地要求书籍标题必须唯一。代码通过设置 unique 选项创建名为 "by_title" 的索引来强制执行此操作。此索引用于按标题查找书籍,并将阻止添加标题重复的书籍。

书籍记录还有一个 "author" 属性,不要求唯一。代码创建了另一个名为 "by_author" 的索引,以允许按该属性进行查找。

代码首先打开数据库连接。upgradeneeded 事件处理器代码会在需要时创建对象仓库和索引。success 事件处理器代码会保存打开的连接,以供后续示例使用。

const request = indexedDB.open("library");
let db;

request.onupgradeneeded = function() {
  // The database did not previously exist, so create object stores and indexes.
  const db = request.result;
  const store = db.createObjectStore("books", {keyPath: "isbn"});
  const titleIndex = store.createIndex("by_title", "title", {unique: true});
  const authorIndex = store.createIndex("by_author", "author");

  // Populate with initial data.
  store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
  store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
  store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
};

request.onsuccess = function() {
  db = request.result;
};

以下示例使用事务填充数据库。

const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");

store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});

tx.oncomplete = function() {
  // All requests have succeeded and the transaction has committed.
};

以下示例使用索引在数据库中按标题查找单本书籍。

const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_title");

const request = index.get("Bedrock Nights");
request.onsuccess = function() {
  const matching = request.result;
  if (matching !== undefined) {
    // A match was found.
    report(matching.isbn, matching.title, matching.author);
  } else {
    // No match was found.
    report(null);
  }
};

以下示例使用索引和游标在数据库中按作者查找所有书籍。

const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_author");

const request = index.openCursor(IDBKeyRange.only("Fred"));
request.onsuccess = function() {
  const cursor = request.result;
  if (cursor) {
    // Called for each matching record.
    report(cursor.value.isbn, cursor.value.title, cursor.value.author);
    cursor.continue();
  } else {
    // No more matching records.
    report(null);
  }
};

以下示例展示了请求失败时处理错误的一种方式。

const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");
const request = store.put({title: "Water Buffaloes", author: "Slate", isbn: 987654});
request.onerror = function(event) {
  // The uniqueness constraint of the "by_title" index failed.
  report(request.error);
  // Could call event.preventDefault() to prevent the transaction from aborting.
};
tx.onabort = function() {
  // Otherwise the transaction will automatically abort due the failed request.
  report(tx.error);
};

当不再需要数据库连接时,可以将其关闭。

db.close();

将来,数据库可能会增长并包含其他对象仓库和索引。以下示例展示了处理旧版本迁移的一种方式。

const request = indexedDB.open("library", 3); // Request version 3.
let db;

request.onupgradeneeded = function(event) {
  const db = request.result;
  if (event.oldVersion < 1) {
    // Version 1 is the first version of the database.
    const store = db.createObjectStore("books", {keyPath: "isbn"});
    const titleIndex = store.createIndex("by_title", "title", {unique: true});
    const authorIndex = store.createIndex("by_author", "author");
  }
  if (event.oldVersion < 2) {
    // Version 2 introduces a new index of books by year.
    const bookStore = request.transaction.objectStore("books");
    const yearIndex = bookStore.createIndex("by_year", "year");
  }
  if (event.oldVersion < 3) {
    // Version 3 introduces a new object store for magazines with two indexes.
    const magazines = db.createObjectStore("magazines");
    const publisherIndex = magazines.createIndex("by_publisher", "publisher");
    const frequencyIndex = magazines.createIndex("by_frequency", "frequency");
  }
};

request.onsuccess = function() {
  db = request.result; // db.version will be 3.
};
同一个数据库可以同时被多个客户端(页面和工作线程)使用——事务确保它们在读写时不会发生冲突。如果一个新客户端想要升级数据库(通过 upgradeneeded 事件),则在所有其他客户端关闭其与当前数据库版本的连接之前,它无法进行升级。

为了避免阻塞新客户端的升级,客户端可以监听 versionchange 事件。当另一个客户端想要升级数据库时,该事件会触发。为了允许升级继续,请通过采取最终关闭该客户端与数据库的连接的操作来响应 versionchange 事件。

执行此操作的一种方法是重新加载页面。

db.onversionchange = function() {
  // First, save any unsaved data:
  saveUnsavedData().then(function() {
    // If the document isn't being actively used, it could be appropriate to reload
    // the page without the user's interaction.
    if (!document.hasFocus()) {
      location.reload();
      // Reloading will close the database, and also reload with the new JavaScript
      // and database definitions.
    } else {
      // If the document has focus, it can be too disruptive to reload the page.
      // Maybe ask the user to do it manually:
      displayMessage("Please reload this page for the latest version.");
    }
  });
};

function saveUnsavedData() {
  // How you do this depends on your app.
}

function displayMessage() {
  // Show a non-modal message to the user.
}

另一种方法是调用连接close() 方法。但是,你需要确保你的应用意识到这一点,因为后续访问数据库的尝试将会失败。

db.onversionchange = function() {
  saveUnsavedData().then(function() {
    db.close();
    stopUsingTheDatabase();
  });
};

function stopUsingTheDatabase() {
  // Put the app into a state where it no longer uses the database.
}

新客户端(尝试升级的那个)可以使用 blocked 事件来检测是否有其他客户端正在阻止升级发生。如果其他客户端在它们的 versionchange 事件触发后仍然持有数据库连接,则会触发 blocked 事件。

const request = indexedDB.open("library", 4); // Request version 4.
let blockedTimeout;

request.onblocked = function() {
  // Give the other clients time to save data asynchronously.
  blockedTimeout = setTimeout(function() {
    displayMessage("Upgrade blocked - Please close other tabs displaying this site.");
  }, 1000);
};

request.onupgradeneeded = function(event) {
  clearTimeout(blockedTimeout);
  hideMessage();
  // ...
};

function hideMessage() {
  // Hide a previously displayed message.
}

只有当另一个客户端未能从数据库断开连接时,用户才会看到上述消息。理想情况下,用户永远不会看到这个。

2. 构造

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

注意: 因此,名称比较对大小写差异以及其他细微差异(例如规范化形式、是否包含控制字符以及 Unicode 文本中的其他变体)敏感。[Charmod-Norm]

如果实现使用的存储机制不支持任意字符串,实现可以使用转义机制或类似方法将提供的名称映射为它可以存储的字符串。

要从列表 names 创建排序名称列表,请执行以下步骤:

  1. sorted 为使用代码单元小于算法升序排序后的 names

  2. 返回一个与 sorted 关联的新 DOMStringList

详细信息这匹配 sort() 方法在 StringArray 上的表现。这种排序方式比较每个字符串中的 16 位代码单元,产生高效、一致且确定的排序顺序。产生的列表不会匹配任何特定的字母表或词典顺序,特别是对于由代理对表示的代码点而言。

2.1. 数据库

每个存储键都关联有一组数据库数据库拥有零个或多个对象仓库,用于保存数据库中存储的数据。

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

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

注意: 每个数据库在同一时间只有一个版本;数据库不能同时存在多个版本。更改版本的唯一方法是使用升级事务

数据库最多关联有一个升级事务,该事务或者是空值,或者是升级事务,初始时为空值。

2.1.1. 数据库连接

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

打开数据库的行为会创建一个连接。在任何给定时间,可能存在多个指向特定数据库连接

连接只能访问与打开该连接的全局作用域的存储键相关联的数据库

注意: 这不受 Documentdomain 更改的影响。

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

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

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

在特殊情况下,用户代理可能会关闭连接,例如由于失去了文件系统访问权限、权限变更或存储键的存储空间被清除。如果发生这种情况,用户代理必须使用连接并设置 强制标志 为 true,运行关闭数据库连接算法。

连接拥有一个对象仓库集合,该集合在连接创建时被初始化为关联数据库对象仓库的集合。集合的内容将保持不变,除非升级事务处于活动状态

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

如果尝试升级或删除数据库,将在打开的连接上触发类型为 versionchange 的事件。这让连接有机会关闭以允许升级或删除继续进行。

如果连接异常关闭,将在该连接上触发类型为 close 的事件。

2.2. 对象仓库

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

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

对象仓库拥有一个记录列表,用于保存对象仓库中的数据。每条记录由一个和一个组成。列表根据键按升序排列。在同一个对象仓库中,不可能存在多条具有相同键的记录。

对象仓库有一个名称,即一个名称。在任何时候,该名称在所属的数据库内都是唯一的。

对象仓库可选拥有一个键路径。如果对象仓库拥有键路径,则称其使用内联键。否则,称其使用离线键

对象仓库可选拥有一个键生成器

对象仓库可以从以下三个来源之一为记录导出

  1. 键生成器。键生成器在每次需要键时生成一个单调递增的数字。

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

  3. 被存储到对象仓库时,键也可以显式指定。

2.2.1. 对象仓库句柄

脚本不直接与对象仓库交互。相反,在事务中,脚本通过对象仓库句柄间接访问。

对象仓库句柄拥有一个关联的对象仓库和一个关联的事务。多个句柄可以与不同事务中的同一个对象仓库相关联,但在同一个事务内,只能有一个与特定对象仓库相关联的对象仓库句柄

对象仓库句柄拥有一个索引集合,在对象仓库句柄创建时,初始化为引用关联对象仓库索引集合。集合的内容将保持不变,除非升级事务处于活动状态

对象仓库句柄有一个名称,在对象仓库句柄创建时,初始化为关联对象仓库名称。除升级事务处于活动状态外,名称将保持不变。

2.3.

每条记录都与一个关联。用户代理必须支持任何可序列化对象。这包括诸如 String 原始值和 Date 对象等简单类型,以及 ObjectArray 实例、File 对象、Blob 对象、ImageData 对象等。记录通过值而非引用进行存储和检索;随后对值进行的更改对数据库中存储的记录没有影响。

记录StructuredSerializeForStorage 操作输出的记录

2.4.

为了有效地检索存储在索引数据库中的记录,每条记录均按照其进行组织。

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

还有一个关联的,若类型为数字日期,则为 unrestricted double;若类型为字符串,则为 DOMString;若类型为二进制,则为字节序列;若类型为数组,则为其他列表

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

注意: 以下 ECMAScript 类型是有效的键:

尝试将其他 ECMAScript 值转换为将会失败。

数组键是类型为数组数组键子键数组键中的项目

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

  1. taa类型

  2. tbb类型

  3. 如果 ta 不等于 tb,则执行以下步骤:

    1. 如果 ta数组,则返回 1。

    2. 如果 tb数组,则返回 -1。

    3. 如果 ta二进制,则返回 1。

    4. 如果 tb二进制,则返回 -1。

    5. 如果 ta字符串,则返回 1。

    6. 如果 tb字符串,则返回 -1。

    7. 如果 ta日期,则返回 1。

    8. 断言tb日期

    9. 返回 -1。

  4. vaa

  5. vbb

  6. ta 上切换:

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

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

    3. 返回 0。

    string
    1. 如果 va代码单元小于 vb,则返回 -1。

    2. 如果 vb代码单元小于 va,则返回 1。

    3. 返回 0。

    二进制:
    1. 如果 va字节小于 vb,则返回 -1。

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

    3. 返回 0。

    array
    1. lengthva大小vb大小中的较小值。

    2. i 为 0。

    3. i 小于 length 时,执行:

      1. c 为递归比较两个键 va[i] 和 vb[i] 的结果。

      2. 如果 c 不为 0,返回 c

      3. i 增加 1。

    4. 如果 va大小大于 vb大小,则返回 1。

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

    6. 返回 0。

如果比较两个键 ab 的结果为 1,则称 a 大于 b

如果比较两个键 ab 的结果为 -1,则称 a 小于 b

如果比较两个键 ab 的结果为 0,则称 a 等于 b

注意: 根据上述规则,负无穷大是的最小值。数字键小于日期键。日期键小于字符串键。字符串键小于二进制键。二进制键小于数组键。不存在最大值。这是因为由任何潜在的最大后跟另一个组成的数组更大。

注意: 二进制键的成员作为无符号字节值(在 0 到 255 范围内,含边界)进行比较,而非有符号 byte 值(在 -128 到 127 范围内,含边界)。

2.5. 键路径

键路径是一个定义如何从中提取的字符串或字符串列表。有效键路径为以下之一:

注意: 键路径中不允许有空格。

键路径值只能从由 StructuredSerializeForStorage 显式复制的属性中访问,以及以下特定类型属性:

类型属性
Blob size, type
File name, lastModified
Array length
字符串 (String) length

2.6. 索引

有时,通过除之外的其他方式检索对象仓库中的记录会很有用。索引允许使用对象仓库记录的属性,在对象仓库中查找记录

索引是一种专门的持久化键值存储,并具有一个引用对象仓库。索引具有一个记录列表,用于保存索引中存储的数据。索引中的记录会在插入、更新或删除引用的对象仓库中的记录时自动填充。可以有多个索引引用同一个对象仓库,对象仓库中的更改会导致所有此类索引得到更新。

索引记录中的始终是索引引用的对象仓库中的值。是使用键路径从引用对象仓库的中导出的。如果索引引用的对象仓库中给定的键为 X记录具有值 A,并且在 A评估索引的键路径得出结果 Y,则索引将包含一条键为 Y、值为 X 的记录。

例如,如果索引的引用对象仓库包含一条键为 123、值为 { name: "Alice", title: "CEO" } 的记录,并且索引的键路径为 "name",则索引将包含一条键为 "Alice"、值为 123 的记录。

索引中的记录被称为拥有引用值。这是索引引用的对象仓库中具有与索引记录的值相等的键的记录的值。因此,在上面的示例中,索引中键为 Y、值为 X 的记录具有 A引用值

在前面的示例中,索引中键为 "Alice"、值为 123 的记录将具有 { name: "Alice", title: "CEO" }引用值

注意: 索引中的每条记录仅引用索引引用的对象仓库中的一条记录。但是,索引中可能有多个记录引用对象仓库中的同一条记录。也可能索引中没有任何记录引用对象仓库中的给定记录。

索引中的记录始终按照记录的键排序。然而,与对象仓库不同,给定索引可以包含多个具有相同键的记录。此类记录会根据索引记录的值(即引用对象仓库中记录的键)进行进一步排序。

索引有一个名称,即一个名称。在任何时候,该名称在索引引用对象仓库内都是唯一的。

索引有一个唯一性标志。当为 true 时,索引强制要求索引中没有两条记录具有相同的键。如果试图插入或修改索引引用的对象仓库中的记录,使得在记录的新值上评估索引的键路径产生的结果已存在于索引中,则对对象仓库的修改尝试失败。

索引有一个多条目标志。此标志影响当评估索引的键路径结果为数组键时索引的行为。如果其多条目标志为 false,则会将一条记录(其数组键)添加到索引中。如果其多条目标志为 true,则会为每个子键向索引中添加一条记录

2.6.1. 索引句柄

脚本不直接与索引交互。相反,在事务中,脚本通过索引句柄间接访问。

索引句柄拥有一个关联的索引和一个关联的对象仓库句柄索引句柄事务即其关联对象仓库句柄事务。多个句柄可以与不同事务中的同一个索引相关联,但在同一个事务内,只能有一个与特定索引相关联的索引句柄

索引句柄有一个名称,在索引句柄创建时,初始化为关联索引名称。除升级事务处于活动状态外,名称将保持不变。

2.7. 事务

事务用于与数据库中的数据交互。无论何时读取或写入数据库数据,都是通过使用事务来完成的。

事务提供了一些防止应用和系统故障的保护。事务可用于存储多条数据记录或有条件地修改某些数据记录。事务代表了一组原子且持久的数据访问和数据变更操作。

所有事务都通过连接创建,该连接即事务的连接

事务拥有一个作用域,即事务可以与之交互的对象仓库集合

注意: 除非事务升级事务,否则事务作用域保持不变。

如果任何对象仓库同时存在于两个事务的作用域中,则这两个事务具有重叠作用域

事务有一个模式,决定了可以在该事务上执行哪些类型的交互。模式在事务创建时设置,并在事务的整个生命周期内保持固定。事务模式为以下之一:

"readonly"

该事务仅允许读取数据。此类事务无法进行任何修改。其优势在于,即使作用域重叠(即使用相同的对象仓库),也可以同时启动多个只读事务。此类事务可以在数据库打开后的任何时间创建。

"readwrite"

该事务允许从现有对象仓库中读取、修改和删除数据。但是,不能添加或删除对象仓库和索引。如果多个 "readwrite" 事务的作用域重叠,则它们不能同时启动,因为这意味着它们可能在事务执行过程中修改彼此的数据。此类事务可以在数据库打开后的任何时间创建。

"versionchange"

该事务允许从现有对象仓库中读取、修改和删除数据,还可以创建和删除对象仓库和索引。它是唯一可以进行此类操作的事务类型。此类事务无法手动创建,而是在触发 upgradeneeded 事件时自动创建。

事务拥有一个持久性提示。这是一个给予用户代理的提示,指示在提交事务时是优先考虑性能还是持久性。持久性提示为以下之一:

"strict"

用户代理可以在验证所有未完成的更改已成功写入持久性存储介质后,才认为该事务已成功提交

"relaxed"

用户代理可以在所有未完成的更改已写入操作系统后(无需后续验证),即认为该事务已成功提交

"default"

用户代理应为存储桶使用其默认的持久性行为。如果未指定,这是事务的默认值。

注意: 在典型实现中,"strict" 是提示用户代理在触发 complete 事件之前刷新任何操作系统 I/O 缓冲区的提示。虽然这提供了更高的可靠性以确保在随后的操作系统崩溃或断电情况下更改会被持久化,但刷新缓冲区可能需要大量时间并消耗移动设备的电量。鼓励 Web 应用对缓存或快速更改的记录等短暂数据使用 "relaxed",并在降低数据丢失风险的重要性超过性能和功耗影响的情况下使用 "strict"。鼓励实现在平衡应用提供的持久性提示与对用户和设备的影响之间权衡。

事务可选拥有一个清理事件循环,该循环是一个事件循环

事务有一个请求列表,用于保存针对该事务发出的待处理请求

事务有一个错误,如果事务中止,该错误会被设置。

注意:实现者需要牢记,值 “null” 被视为一种错误,因为它是由 abort() 设置的。

事务获取父级算法返回该事务的连接

只读事务模式为“readonly”的事务

读/写事务模式为“readwrite”的事务

2.7.1. 事务生命周期

事务拥有一个状态,该状态为以下之一:

active

当事务首次被创建时,以及在分发与该事务关联的请求的事件期间,事务处于此状态。

当事务处于此状态时,可以针对该事务发起新的请求

inactive (不活跃)

当事务创建后控制权返回事件循环,且未进行事件分发时,事务处于此状态。

当事务处于此状态时,不能针对该事务发起任何请求

正在提交 (committing)

一旦与事务关联的所有请求完成,事务在尝试提交时将进入此状态。

当事务处于此状态时,不能针对该事务发起任何请求

finished (已完成)

一旦事务提交或中止,它将进入此状态。

当事务处于此状态时,不能针对该事务发起任何请求

事务应该是短生命周期的。下述的自动提交功能鼓励这样做。

注意:作者仍可能使事务长期存活;然而,不建议使用此模式,因为它可能导致糟糕的用户体验。

事务生命周期如下:

  1. 事务在作用域模式下被创建。当事务被创建时,其状态初始为活跃 (active)

  2. 当实现能够强制执行事务的作用域模式约束(定义在下文)时,实现必须加入一个数据库任务队列以异步启动该事务。

    一旦事务被启动,实现即可开始执行针对该事务的请求。请求必须按照针对该事务发起的顺序执行。同样,它们的结果必须按照特定事务中发起请求的顺序返回。对于不同事务中的请求结果返回顺序没有保证。

    注意:事务模式确保针对不同事务发起的两个请求可以以任何顺序执行,而不会影响存储在数据库中的最终数据。

  3. 当与事务关联的每个请求处理时,将触发一个 successerror 事件。在分发事件期间,事务状态被设置为活跃,允许发起额外的请求。事件分发完成后,事务状态再次被设置为不活跃 (inactive)

  4. 事务可以在其完成前的任何时刻被中止 (abort),即使该事务当前未处于活跃状态或尚未启动

    abort() 的显式调用将发起一次中止。在未被脚本处理的请求失败后,也会发起中止。

    当事务中止时,实现必须撤销(回滚)在该事务期间对数据库所做的任何更改。这包括对对象存储内容的更改,以及对对象存储索引的添加和移除。

  5. 当针对事务发起的所有请求已完成且其返回结果已处理,没有针对事务发起新的请求,且事务未被中止时,实现必须尝试提交不活跃事务。

    commit() 的显式调用将发起一次提交,而不必等待脚本处理请求结果。

    提交时,事务状态被设置为正在提交。实现必须原子地写入由针对该事务的请求所做的对数据库的任何更改。也就是说,要么写入所有更改;如果发生错误(例如磁盘写入错误),实现不得将任何更改写入数据库,并且将遵循中止事务的步骤。

  6. 当事务被提交中止时,其状态被设置为完成

实现必须允许在事务活跃时,针对该事务发起请求。即使事务尚未启动,也是如此。在事务启动之前,实现不得执行这些请求;然而,实现必须跟踪这些请求及其顺序。

事务从其被创建直到其状态被设置为完成期间,被称为存活 (live)

清理 Indexed Database 事务,请运行以下步骤。如果清理了任何事务,它们将返回 true,否则返回 false。

  1. 如果没有事务清理事件循环与当前事件循环匹配,则返回 false。

  2. 对于每个事务 transaction,其清理事件循环与当前事件循环匹配:

    1. 设置 transaction状态不活跃

    2. 清除 transaction清理事件循环

  3. 返回 true。

注意:这些步骤由 [HTML] 调用。它们确保通过脚本调用 transaction() 创建的事务在调用该脚本的任务完成后被停用。对于每个事务,这些步骤最多运行一次。

类型为 complete 的事件会在已成功提交事务上触发。

类型为 abort 的事件会在已中止事务上触发。

2.7.2. 事务调度

以下约束定义了事务何时可以启动

实现可能会施加额外的约束。例如,实现不需要并行启动重叠读/写事务,或者可能对启动的事务数量施加限制。

注意:这些约束意味着以下内容:

2.7.3. 升级事务

升级事务模式为“versionchange”的事务

在打开与数据库连接后,如果指定了大于当前版本版本,则在运行升级数据库的步骤时,会自动创建升级事务。此事务将在 upgradeneeded 事件处理程序内处于活跃状态。

注意:升级事务支持在数据库中创建、重命名和删除对象存储索引升级事务是排他的。打开数据库连接的步骤确保当升级事务处于存活状态时,只有一个到数据库的连接是打开的。upgradeneeded 事件不会被触发,因此升级事务不会启动,直到所有其他到相同数据库连接都已关闭。这确保了所有先前的事务都已完成

只要升级事务处于存活状态,尝试打开更多到相同数据库连接就会被延迟,并且任何通过调用 transaction() 试图使用同一连接来启动额外事务的操作都会抛出异常。这确保了没有其他事务并发存活,同时也确保了只要升级事务处于存活状态,就不会有新的事务针对同一数据库排队。

这进一步确保了一旦升级事务完成,数据库中的对象存储索引集合在所有后续连接事务的生命周期内保持不变。

2.8. 请求

数据库的每个异步操作都是使用请求完成的。每个请求代表一个操作。

请求拥有一个已处理标志 (processed flag),初始为 false。当与请求关联的操作被执行时,此标志被设置为 true。

请求已处理标志为 true 时,称该请求已被处理

请求拥有一个完成标志 (done flag),初始为 false。当与请求关联的操作结果可用时,此标志被设置为 true。

请求拥有一个源 (source)对象。

请求拥有一个结果和一个错误,在完成标志为 true 之前,两者均不可访问。

请求拥有一个事务,初始为 null。当使用异步执行请求的步骤将请求发起事务中时,此项将被设置。

当发出一个请求时,返回一个新的请求,其完成标志设置为 false。如果请求成功完成,其完成标志被设置为 true,其结果被设置为请求的结果,并且类型为 success 的事件会在该请求上触发。

如果执行操作时发生错误,则请求的完成标志被设置为 true,请求的错误被设置为该错误,并且类型为 error 的事件会在该请求上触发。

请求获取父级算法返回该请求的事务

注意:请求通常不会被重用,但也有例外。当游标进行迭代时,迭代的成功与否是在用于打开游标的同一个请求对象上报告的。当升级事务是必需时,同一个打开请求既用于 upgradeneeded 事件,也用于打开操作本身的最终结果。在某些情况下,请求的完成标志会被设置为 false,然后再次设置为 true,结果可能会改变,或者可能会设置错误

2.8.1. 打开请求

打开请求是一种特殊的请求类型,用于打开连接或删除数据库。除了 successerror 事件外,blockedupgradeneeded 事件可能会在打开请求上触发,以指示进度。

打开请求始终为 null。

打开请求事务为 null,除非已经触发了 upgradeneeded 事件。

打开请求获取父级算法返回 null。

2.8.2. 连接队列

打开请求连接队列中处理。该队列包含所有与存储键名称关联的打开请求。添加到连接队列的请求按顺序处理,每个请求必须运行至完成,下一个请求才能被处理。一个打开请求可能会被其他连接阻塞,需要这些连接关闭,请求才能完成并允许处理后续请求。

注意:连接队列不是与事件循环关联的任务队列,因为请求是在任何特定浏览上下文之外处理的。向已完成的打开请求交付事件仍会经过与发出请求上下文的事件循环关联的任务队列

2.9. 键范围

可以使用键范围对象存储索引中检索记录。键范围是用于键的某种数据类型上的连续区间。

键范围有一个关联的下界(null 或一个)。

键范围有一个关联的上界(null 或一个)。

键范围有一个关联的下开标志。除非另有说明,它为 false。

键范围有一个关联的上开标志。除非另有说明,它为 false。

键范围可以有一个下界等于上界键范围下界不得大于上界

仅包含 key键范围下界上界都等于 key

如果满足以下两个条件,则key 处于键范围 range 中:

无界键范围键范围,其下界上界均等于 null。所有处于无界键范围中。

将值转换为键范围(具有 value 和可选的 null 不允许标志),请运行以下步骤:

  1. 如果 value键范围,则返回 value

  2. 如果 value 为 undefined 或 null,则如果 null 不允许标志为 true,则抛出一个 "DataError" DOMException;否则返回无界键范围

  3. key 为使用 value 将值转换为键的结果。重新抛出任何异常。

  4. 如果 key 为 “invalid value” 或 “invalid type”,则抛出一个 "DataError" DOMException

  5. 返回一个键范围仅包含 key

潜在有效键范围是一个 ECMAScript 值,其类型可转换为键范围。特定值是否会成功转换为键范围(即对其执行将值转换为键范围操作是否抛出异常)并不相关。

注意:例如,已分离的 BufferSource 是一个潜在有效键范围,当与将值转换为键范围一起使用时会抛出异常。

要确定一个值何时是潜在有效键范围(具有 ECMAScript value),请运行以下步骤:

  1. 如果 value键范围,则返回 true。

  2. key 为使用 value 将值转换为键的结果。

  3. 如果 key 为 “invalid type”,则返回 false。

  4. 否则返回 true。

注意:getAll()getAllKeys() 方法使用是潜在有效键范围来处理它们的第一个参数。如果该参数是潜在有效键范围getAll()getAllKeys() 使用该参数运行将值转换为键范围。否则,IDBGetAllOptions 将用于第一个参数。getAll()getAllKeys() 对第一个参数为 DateArrayArrayBuffer 的情况会抛出异常,当它们与将值转换为键一起使用时,会返回 “invalid value”。例如,使用 NaN Date 作为第一个参数运行 getAll() 会抛出异常,而不是成功使用具有默认值的 IDBGetAllOptions 字典。

2.10. 游标

游标用于在索引对象存储中的一系列记录上以特定方向进行迭代。

游标有一个源句柄 (source handle),即打开游标的索引句柄对象存储句柄

游标有一个事务,即来自游标源句柄事务

游标索引对象存储中拥有记录的范围 (range)

游标有一个源 (source),即来自游标源句柄索引对象存储。游标的指示游标正在迭代其记录的索引对象存储是哪一个。如果游标的源句柄索引句柄,则游标的该索引句柄关联的索引。否则,游标的该对象存储句柄关联的对象存储

游标有一个方向,它决定了迭代时是按单调递增还是递减顺序移动记录键,以及在迭代索引时是否跳过重复值。游标的方向还决定了游标的初始位置是在其的开头还是末尾。游标的方向是以下之一:

"next"

此方向导致游标在的开头打开。迭代时,游标应以按键单调递增的顺序产生所有记录(包括重复项)。

"nextunique"

此方向导致游标在的开头打开。迭代时,游标不应产生具有相同键的记录,但除此之外,应以按键单调递增的顺序产生所有记录。对于每个具有重复值的键,仅产生第一条记录。当对象存储索引且其唯一标志设置为 true 时,此方向的行为与 "next" 完全相同。

"prev"

此方向导致游标在的末尾打开。迭代时,游标应以按键单调递减的顺序产生所有记录(包括重复项)。

"prevunique"

此方向导致游标在的末尾打开。迭代时,游标不应产生具有相同键的记录,但除此之外,应以按键单调递减的顺序产生所有记录。对于每个具有重复值的键,仅产生第一条记录。当对象存储索引且其唯一标志设置为 true 时,此方向的行为与 "prev" 完全相同。

游标在其范围内的位置。游标正在迭代的记录列表可能在游标完整范围迭代完成之前发生变化。为了处理这一点,游标不将它们的位置作为索引来维护,而是作为先前返回记录的来维护。对于前向迭代游标,下一次游标被要求迭代到下一条记录时,它会返回大于先前返回的的最低的记录。对于反向迭代游标,情况相反,它返回小于先前返回的的最高的记录。

对于迭代索引的游标,情况稍微复杂一些,因为多条记录可以具有相同的键,因此也按排序。迭代索引时,游标还有一个对象存储位置,它指示索引中先前找到的记录。在查找下一个适当的记录时,位置对象存储位置都会被使用。

游标有一个和一个,它们代表上次迭代的记录

游标有一个got value 标志。当此标志为 false 时,游标要么正在加载下一个值,要么已达到其范围的末尾。当它为 true 时,表示游标当前持有值,并且已准备好迭代到下一个值。

如果游标的对象存储,则游标的有效对象存储是该对象存储,而游标的有效键是游标的位置。如果游标的索引,则游标的有效对象存储是该索引的引用的对象存储,而有效键是游标的对象存储位置

游标有一个请求,即用于打开游标的请求

游标还有一个仅键标志,用于指示游标的是否通过 API 公开。

2.11. 键生成器

当创建对象存储时,可以指定使用键生成器。如果未另外指定,键生成器将用于为插入到对象存储中的记录生成键。

键生成器拥有一个当前编号。该当前编号始终是一个正整数,且小于或等于 253 (9007199254740992) + 1。键生成器当前编号的初始值为 1,在关联的对象存储创建时设置。当前编号随着键的生成而递增,并且可以通过使用显式键更新为特定值。

注意:每个使用键生成器的对象存储都使用单独的生成器。也就是说,与一个对象存储的交互绝不会影响任何其他对象存储的键生成器。

修改键生成器的当前编号被视为数据库操作的一部分。这意味着如果操作失败且操作被撤销,当前编号将恢复为操作开始之前的值。这既适用于由于生成键时当前编号增加 1 而发生的修改,也适用于由于在存储记录的调用中指定了键值而存储记录而发生的修改。

同样,如果事务被中止,事务作用域中每个对象存储的键生成器的当前编号将恢复为事务开始之前的值。

键生成器的当前编号绝不会减少,除非是数据库操作被撤销的结果。从对象存储中删除记录绝不会影响对象存储的键生成器。即使清除对象存储中的所有记录(例如使用 clear() 方法),也不会影响对象存储键生成器的当前编号

当存储记录且在存储记录的调用中未指定时,会生成一个键。

要为对象存储 store 生成键,请运行以下步骤:

  1. generatorstore键生成器

  2. keygenerator当前编号

  3. 如果 key 大于 253 (9007199254740992),则返回失败。

  4. generator当前编号增加 1。

  5. 返回 key

当存储记录且在存储记录的调用中指定了时,关联的键生成器可能会被更新。

可能更新具有 key对象存储 store 的键生成器,请运行以下步骤:

  1. 如果 key类型不是 number,则中止这些步骤。

  2. valuekey

  3. value 设置为 value 和 253 (9007199254740992) 中的最小值。

  4. value 设置为不大于 value 的最大整数。

  5. generatorstore键生成器

  6. 如果 value 大于或等于 generator当前编号,则将 generator当前编号设置为 value + 1。

注意:既可以为使用行内键的对象存储指定键(通过设置存储值上的属性,即对象存储键路径指向的属性),也可以为使用行外键的对象存储指定键(通过将键参数传递给存储记录的调用)。只有number类型的指定键会影响键生成器的当前编号datearray(无论它们包含的其他键是什么)、binarystring(无论它们是否可以被解析为数字)类型的键不会对键生成器的当前编号产生影响。类型number小于 1 的键不会影响当前编号,因为它们始终低于当前编号

当键生成器的当前编号达到 253 (9007199254740992) 以上时,任何后续使用该键生成器生成新的尝试都将导致 "ConstraintError" DOMException。仍可以通过指定显式键将记录插入到对象存储中,但是对于此类记录,再次使用键生成器的唯一方法是删除该对象存储并创建一个新的。

注意:此限制的产生是因为大于 9007199254740992 的整数不能唯一地表示为 ECMAScript Number。例如,在 ECMAScript 中 9007199254740992 + 1 === 9007199254740992只要正常使用键生成器,此限制就不会成为问题。如果您每秒生成 1000 个新键,日夜不停,您在超过 285000 年内都不会遇到此限制。

其实际结果是,为对象存储生成的第一个键始终是 1(除非首先插入了更高的数字键),并且为对象存储生成的键始终是大于存储中最高数字键的正整数。对于同一对象存储,同一键永远不会生成两次,除非事务被回滚。

每个对象存储都有自己的键生成器

store1 = db.createObjectStore("store1", { autoIncrement: true });
store1.put("a"); // Will get key 1
store2 = db.createObjectStore("store2", { autoIncrement: true });
store2.put("a"); // Will get key 1
store1.put("b"); // Will get key 2
store2.put("b"); // Will get key 2

如果由于约束冲突或 IO 错误导致插入失败,键生成器不会更新。

transaction.onerror = function(e) { e.preventDefault() };
store = db.createObjectStore("store1", { autoIncrement: true });
index = store.createIndex("index1", "ix", { unique: true });
store.put({ ix: "a"}); // Will get key 1
store.put({ ix: "a"}); // Will fail
store.put({ ix: "b"}); // Will get key 2

从对象存储中删除项绝不会影响键生成器。包括调用 clear() 时。

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.delete(1);
store.put("b"); // Will get key 2
store.clear();
store.put("c"); // Will get key 3
store.delete(IDBKeyRange.lowerBound(0));
store.put("d"); // Will get key 4

插入带有显式键的项仅当键为数字且高于最后生成的键时,才会影响键生成器。

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.put("b", 3); // Will use key 3
store.put("c"); // Will get key 4
store.put("d", -10); // Will use key -10
store.put("e"); // Will get key 5
store.put("f", 6.00001); // Will use key 6.0001
store.put("g"); // Will get key 7
store.put("f", 8.9999); // Will use key 8.9999
store.put("g"); // Will get key 9
store.put("h", "foo"); // Will use key "foo"
store.put("i"); // Will get key 10
store.put("j", [1000]); // Will use key [1000]
store.put("k"); // Will get key 11
// All of these would behave the same if the objectStore used a
// keyPath and the explicit key was passed inline in the object

中止事务会回滚事务期间发生的任何对键生成器的增加。这是为了使所有回滚保持一致,因为因崩溃而发生的回滚永远没有机会提交增加的键生成器值。

db.createObjectStore("store", { autoIncrement: true });
trans1 = db.transaction(["store"], "readwrite");
store_t1 = trans1.objectStore("store");
store_t1.put("a"); // Will get key 1
store_t1.put("b"); // Will get key 2
trans1.abort();
trans2 = db.transaction(["store"], "readwrite");
store_t2 = trans2.objectStore("store");
store_t2.put("c"); // Will get key 1
store_t2.put("d"); // Will get key 2

以下示例说明了在使用行内键生成器将对象保存到对象存储时,不同行为的各种情况。

如果以下条件为真:

那么由键生成器提供的值将被用于填充键值。在下面的示例中,对象存储的键路径为 "foo.bar"。实际对象没有 bar 属性的值,即 { foo: {} }。当对象保存到对象存储时,bar 属性被分配值 1,因为这是由键生成器生成的下一个

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
};

如果以下条件为真:

那么与键路径属性关联的值将被使用。自动生成的不会被使用。在下面的示例中,对象存储键路径为 "foo.bar"。实际对象对于 bar 属性有 10 的值,即 { foo: { bar: 10} }。当对象保存到对象存储时,bar 属性保持其值 10,因为那是键值。

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: { bar: 10 } }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 10);
};

以下示例说明了通过键路径定义了指定行内,但没有与其匹配的属性的场景。然后,由键生成器提供的值将被用于填充键值,系统负责创建满足层次结构链上属性依赖关系所需的所有属性。在下面的示例中,对象存储键路径为 "foo.bar.baz"。实际对象没有 foo 属性的值,即 { zip: {} }。当对象保存到对象存储时,会创建 foobarbaz 属性,每一个都是另一个的子级,直到可以为 foo.bar.baz 分配值。foo.bar.baz 的值是对象存储生成的下一个键。

const store = db.createObjectStore("store", { keyPath: "foo.bar.baz",
                                              autoIncrement: true });
store.put({ zip: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
  store.get(key).onsuccess = function(e) {
    const value = e.target.result;
    // value will be: { zip: {}, foo: { bar: { baz: 1 } } }
    console.assert(value.foo.bar.baz === 1);
  };
};

尝试在基元值上存储属性将会失败并抛出错误。在下面的第一个示例中,对象存储的键路径为 "foo"。实际对象是一个值为 4 的基元。尝试在该基元值上定义属性会失败。

const store = db.createObjectStore("store", { keyPath: "foo", autoIncrement: true });

// The key generation will attempt to create and store the key path
// property on this primitive.
store.put(4); // will throw DataError

2.12. 记录快照

记录快照包含从对象存储记录索引记录中复制的键和值。

记录快照有一个,它是一个

记录快照有一个,它是一个

注意:对于索引记录,快照的是该记录的引用值的副本。对于对象存储记录,快照的是该记录的值

记录快照还有一个主键,它是一个

注意:对于索引记录,快照的主键是该记录的,即该记录在索引的引用对象存储中的键。对于对象存储记录,快照的主键是同一个,即该记录的键

3. 异常

本文档中使用的每个异常都是一个 DOMException 或派生自 DOMException 的接口,如 [WEBIDL] 中所定义。

下表列出了本文档中使用的 DOMException 名称及其用法说明。

类型描述
AbortError 请求被中止。
ConstraintError 事务中的修改操作失败,因为未满足约束条件。
DataCloneError 正在存储的数据无法通过内部结构化克隆算法进行克隆。
DataError 提供给操作的数据不符合要求。
InvalidAccessError 对对象执行了无效操作。
InvalidStateError 在不允许调用的对象上调用了某个操作,或者在不允许的时间调用了该操作,或者请求是在已被删除或移除的源对象上发出的。
NotFoundError 操作失败,因为找不到请求的数据库对象。
NotReadableError 操作失败,因为无法读取包含请求数据的底层存储。
SyntaxError keyPath 参数包含无效的键路径。
ReadOnlyError 在只读事务中尝试了修改操作。
TransactionInactiveError 向当前处于非活动状态或已完成的事务提交了请求。
UnknownError 操作因与数据库本身无关或未被其他错误涵盖的临时原因而失败。
VersionError 尝试使用低于现有版本的版本打开数据库。

除了上述 DOMException 名称外,如果操作因剩余存储空间不足,或已达到存储配额且用户拒绝为数据库提供更多空间而失败,则应使用 QuotaExceededError 异常类型。

注意: 鉴于多个 Indexed DB 操作可能会抛出相同类型的错误,甚至单个操作也可能因多种原因抛出相同类型的错误,建议实现提供更具体的错误消息,以便开发者识别错误原因。

4. API

API 方法返回时不会阻塞调用线程。所有异步操作都会立即返回一个 IDBRequest 实例。此对象最初不包含有关操作结果的任何信息。一旦信息可用,就会在该请求上触发一个事件,并且该信息可以通过 IDBRequest 实例的属性获取。

这些任务的 任务源数据库访问任务源

排队一个数据库任务,请在 数据库访问任务源 上执行 排队任务

4.1. IDBRequest 接口

IDBRequest 接口提供了使用 事件处理程序 IDL 属性 [HTML] 访问对 数据库数据库 对象发出的异步请求结果的方法。

每个用于发出异步请求的方法都会返回一个 IDBRequest 对象,该对象通过事件与请求应用程序通信。这种设计意味着在任何给定时间,任何 数据库 上都可以有任意数量的活跃请求。

在以下示例中,我们异步打开了一个 数据库。注册了各种事件处理程序以应对各种情况。

const request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {...};
request.onerror = function(evt) {...};
[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"
};
request . result

当请求完成时,返回 结果,如果请求失败,则返回 undefined。如果请求仍处于挂起状态,则抛出 "InvalidStateError" DOMException

request . error

当请求完成时,返回 错误(一个 DOMException),如果请求成功,则返回 null。如果请求仍处于挂起状态,则抛出 "InvalidStateError" DOMException

request . source

返回发出请求的 IDBObjectStoreIDBIndexIDBCursor,如果是 打开请求,则返回 null。

request . transaction

返回发出请求所在的 IDBTransaction。如果是 打开请求,则在 活跃 时返回 升级事务,否则返回 null。

request . readyState

在请求完成之前返回 "pending",完成后返回 "done"。

result 获取器步骤为
  1. 如果 此对象完成标志 为 false,则 抛出 "InvalidStateError" DOMException

  2. 返回 此对象结果,如果请求导致错误,则返回 undefined。

error 获取器步骤为
  1. 如果 此对象完成标志 为 false,则 抛出 "InvalidStateError" DOMException

  2. 返回 此对象错误,如果未发生错误,则返回 null。

source 获取器步骤为返回 此对象来源,如果未设置 来源,则返回 null。

transaction 获取器步骤为返回 此对象事务

注意: transaction 获取器对于某些请求(例如从 open() 返回的 请求)可能返回 null。

readyState 获取器步骤为:如果 此对象完成标志 为 false,则返回 "pending",否则返回 "done"。

onsuccess 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型success

onerror 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型error 事件。

IDBDatabase 上返回 打开请求 的方法使用扩展接口,以允许监听 blockedupgradeneeded 事件。

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

onblocked 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型blocked

onupgradeneeded 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型upgradeneeded

4.2. 事件接口

本规范使用以下自定义接口触发事件

[Exposed=(Window,Worker)]
interface IDBVersionChangeEvent : Event {
  constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
  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;
};

oldVersion 获取器步骤为返回其初始化时设置的值。它表示数据库的上一个版本。

newVersion 获取器步骤为返回其初始化时设置的值。它表示数据库的新版本,如果数据库正在被删除,则返回 null。参见 升级数据库 的步骤。

事件的构造按照 DOM § 2.5 构造事件 定义。

触发一个版本更改事件,命名为 e,在 target 上,给定 oldVersionnewVersion,运行这些步骤

  1. event 为使用 IDBVersionChangeEvent 创建事件 的结果。

  2. eventtype 属性设置为 e

  3. eventbubblescancelable 属性设置为 false。

  4. eventoldVersion 属性设置为 oldVersion

  5. eventnewVersion 属性设置为 newVersion

  6. legacyOutputDidListenersThrowFlag 为 false。

  7. 分派 eventtarget,使用 legacyOutputDidListenersThrowFlag

  8. 返回 legacyOutputDidListenersThrowFlag

    注意: 此算法的返回值并不总是被使用。

4.3. IDBFactory 接口

数据库 对象通过 IDBFactory 接口上的方法访问。在支持 Indexed DB 操作的环境的全局作用域中,存在一个实现此接口的单一对象。

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

indexedDB 属性为应用程序提供了访问索引数据库功能的机制。

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

  Promise<sequence<IDBDatabaseInfo>> databases();

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

dictionary IDBDatabaseInfo {
  DOMString name;
  unsigned long long version;
};
request = indexedDB . open(name)

尝试打开一个到名为 name数据库连接,使用当前版本,如果不存在则使用 1。如果请求成功,requestresult 将为该 连接

request = indexedDB . open(name, version)

尝试打开一个到名为 name数据库连接,使用指定的 version。如果数据库已经存在且版本较低,且存在响应 versionchange 事件未关闭的打开 连接,则请求将被阻塞,直到它们全部关闭,然后进行升级。如果数据库已经存在且版本较高,则请求将失败。如果请求成功,requestresult 将为该 连接

request = indexedDB . deleteDatabase(name)

尝试删除名为 name数据库。如果数据库已经存在且存在响应 versionchange 事件未关闭的打开 连接,则请求将被阻塞,直到它们全部关闭。如果请求成功,requestresult 将为 null。

result = await indexedDB . databases()

返回一个 promise,该 promise 解析为一个对象列表,提供 存储键 内数据库名称和版本的快照。

此 API 旨在供 Web 应用程序自省数据库的使用情况,例如清理网站代码的旧版本。请注意,结果是一个快照;对于此上下文或其他上下文创建、升级或删除数据库的请求,不保证数据的收集顺序或响应的传递顺序。

open(name, version) 方法步骤为

  1. 如果 version 为 0,则 抛出 一个 TypeError

  2. environment此对象相关设置对象

  3. storageKey 为运行 获取存储键 给定 environment 的结果。如果返回失败,则 抛出 "SecurityError" DOMException 并中止这些步骤。

  4. request 为一个新的 打开请求

  5. 并行方式运行这些步骤

    1. result打开数据库连接 的结果,包含 storageKeyname、如果给定则包含 version 否则为 undefined,以及 request

      如果未提供 version 会发生什么?如果未提供 version 且同名的 数据库 已经存在,则连接将打开而不更改 版本。如果未提供 version 且不存在同名的 数据库,则将创建一个 版本 为 1 的新 数据库
    2. request已处理标志 设置为 true。

    3. 排队一个数据库任务 以运行以下步骤

      1. 如果 result 是错误,则

        1. request结果 设置为 undefined。

        2. request错误 设置为 result

        3. request完成标志 设置为 true。

        4. 触发一个事件,命名为 error,在 request 上,其 bubblescancelable 属性初始化为 true。

      2. 否则

        1. request结果 设置为 result

        2. request完成标志 设置为 true。

        3. 触发一个事件,命名为 success,在 request 上。

        注意: 如果上述步骤导致执行了 升级事务,则这些步骤将在该事务完成后运行。这确保了在即将发生另一次版本升级的情况下,success 事件会首先在连接上触发,以便脚本有机会为 versionchange 事件注册监听器。

        为什么不使用 触发 success 事件触发 error 事件 的步骤?该请求(此时)没有关联的事务,因此那些在分派前激活关联事务并在分派后停用事务的步骤不适用。
  6. request 返回一个新的 IDBOpenDBRequest 对象。

deleteDatabase(name) 方法步骤为

  1. environment此对象相关设置对象

  2. storageKey 为运行 获取存储键 给定 environment 的结果。如果返回失败,则 抛出 "SecurityError" DOMException 并中止这些步骤。

  3. request 为一个新的 打开请求

  4. 并行运行这些步骤 并行运行

    1. result删除数据库 的结果,包含 storageKeynamerequest

    2. request已处理标志 设置为 true。

    3. 排队一个数据库任务 以运行以下步骤

      1. 如果 result 是错误,则将 request错误 设置为 result,将 request完成标志 设置为 true,并 触发一个事件,命名为 error,在 request 上,其 bubblescancelable 属性初始化为 true。

      2. 否则,将 request结果 设置为 undefined,将 request完成标志 设置为 true,并 触发一个版本更改事件,命名为 success,在 request 上,使用 result 和 null。

        为什么不使用 触发 success 事件触发 error 事件 的步骤?请求没有关联的事务,因此那些在分派前激活关联事务并在分派后停用事务的步骤不适用。此外,这里的 success 事件是一个 IDBVersionChangeEvent,其中包含了 oldVersionnewVersion 的详细信息。
  5. request 返回一个新的 IDBOpenDBRequest 对象。

databases() 方法步骤为

  1. environment此对象相关设置对象

  2. storageKey 为运行 获取存储键 给定 environment 的结果。如果返回失败,则返回 一个被拒绝的 promise,包含一个 "SecurityError" DOMException

  3. p一个新的 promise

  4. 并行运行这些步骤 并行运行

    1. databasesstorageKey 中的 数据库集合。如果因任何原因无法确定,则 排队一个数据库任务拒绝 p,并返回适当的错误(例如 "UnknownError" DOMException)并终止这些步骤。

    2. result 为一个新的 列表

    3. 对于每个 databases 中的 db

      1. 如果 db版本 为 0,则 继续

      2. info 为一个新的 IDBDatabaseInfo 字典。

      3. infoname 字典成员设置为 db名称

      4. infoversion 字典成员设置为 db版本

      5. 追加 inforesult

    4. 排队一个数据库任务解析 p,使用 result

  5. 返回 p

🚧 databases() 方法是本版本新增的。它在 Chrome 71、Edge 79、Firefox 126 和 Safari 14 中得到支持。 🚧
result = indexedDB . cmp(key1, key2)

比较两个值作为 。如果 key1 先于 key2,则返回 -1;如果 key2 先于 key1,则返回 1;如果键相等,则返回 0。

如果任何一个输入不是有效的 ,则抛出 "DataError" DOMException

cmp(first, second) 方法步骤为

  1. a将值转换为键 的结果,使用 first。重新抛出任何异常。

  2. 如果 a 为 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

  3. b将值转换为键 的结果,使用 second。重新抛出任何异常。

  4. 如果 b 为 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

  5. 返回 比较两个键 的结果,使用 ab

4.4. IDBDatabase 接口

IDBDatabase 接口代表一个到 数据库连接

如果其关联的 连接关闭挂起标志 为 false,且注册了一个或多个类型为 aborterrorversionchange 的事件监听器,则 IDBDatabase 对象不得被垃圾回收。如果一个 IDBDatabase 对象被垃圾回收,则必须 关闭 关联的 连接

[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",
                                         optional IDBTransactionOptions options = {});
  undefined close();

  [NewObject] IDBObjectStore createObjectStore(
    DOMString name,
    optional IDBObjectStoreParameters options = {});
  undefined deleteObjectStore(DOMString name);

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

enum IDBTransactionDurability { "default", "strict", "relaxed" };

dictionary IDBTransactionOptions {
  IDBTransactionDurability durability = "default";
};

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

返回数据库的 名称

connection . version

返回数据库的 版本

name 获取器步骤为返回 此对象 关联的 数据库名称

注意: 即使 此对象关闭挂起标志 为 true,name 属性也会返回此名称。换句话说,此属性的值在 IDBDatabase 实例的生命周期内保持不变。

version 获取器步骤为返回 此对象版本

这与 数据库版本 相同吗?只要 连接 处于打开状态,它就与已连接的 数据库版本 相同。但一旦 连接 关闭,此属性将不会反映稍后通过 升级事务 所做的更改。
connection . objectStoreNames

返回数据库中 对象存储 的名称列表。

store = connection . createObjectStore(name [, options])

创建一个具有给定 nameoptions 的新 对象存储,并返回一个新的 IDBObjectStore

如果未在 升级事务 中调用,则抛出 "InvalidStateError" DOMException

connection . deleteObjectStore(name)

删除名为 name对象存储

如果未在 升级事务 中调用,则抛出 "InvalidStateError" DOMException

objectStoreNames 获取器步骤为
  • names此对象对象存储集合对象存储名称 列表

  • 返回 创建排序名称列表 names 的结果(一个 DOMStringList)。

  • 这与 数据库对象存储 名称 相同吗?只要 连接 处于打开状态,它就与已连接的 数据库对象存储 名称 相同。但一旦 连接 关闭,此属性将不会反映稍后通过 升级事务 所做的更改。

    createObjectStore(name, options) 方法步骤为

    1. database此对象 关联的 数据库

    2. transactiondatabase升级事务(如果不是 null),否则 抛出 "InvalidStateError" DOMException

    3. 如果 transaction状态 不为 活跃,则 抛出 "TransactionInactiveError" DOMException

    4. keyPathoptionskeyPath 成员(如果它不是 undefined 或 null),否则为 null。

    5. 如果 keyPath 不为 null 且不是 有效的键路径,则 抛出 "SyntaxError" DOMException

    6. 如果 database 中已存在 命名为 name对象存储,则 抛出 "ConstraintError" DOMException

    7. autoIncrementoptionsautoIncrement 成员。

    8. 如果 autoIncrement 为 true 且 keyPath 为空字符串或任何序列(空或非空),则 抛出 "InvalidAccessError" DOMException

    9. storedatabase 中的一个新的 对象存储。将创建的 对象存储名称 设置为 name。如果 autoIncrement 为 true,则创建的 对象存储 使用 键生成器。如果 keyPath 不为 null,则将创建的 对象存储键路径 设置为 keyPath

    10. 返回一个与 storetransaction 关联的新的 对象存储句柄

    此方法在 已连接数据库 中创建并返回具有给定名称的新 对象存储。请注意,此方法只能在 升级事务 中调用。

    此方法同步修改在其上调用的 IDBDatabase 实例上的 objectStoreNames 属性。

    在某些实现中,在 createObjectStore() 方法返回后,在排队创建一个 对象存储 的任务后,实现可能会遇到问题。例如,在元数据被异步插入到数据库中,或者实现可能因配额原因需要询问用户权限的实现中。此类实现仍必须创建并返回一个 IDBObjectStore 对象,一旦实现确定创建 对象存储 已失败,就必须使用 中止事务 的步骤使用适当的错误来中止事务。例如,如果创建 对象存储 因配额原因失败,则必须将 QuotaExceededError 用作错误。

    deleteObjectStore(name) 方法步骤为

    1. database此对象 关联的 数据库

    2. transactiondatabase升级事务(如果不是 null),否则 抛出 "InvalidStateError" DOMException

    3. 如果 transaction状态 不为 活跃,则 抛出 "TransactionInactiveError" DOMException

    4. storedatabase命名为 name对象存储,如果不存在,则 抛出 "NotFoundError" DOMException

    5. 此对象对象存储集合 中移除 store

    6. 如果存在与 storetransaction 关联的 对象存储句柄,则从其 索引集合 中移除所有条目。

    7. 销毁 store

    此方法在 已连接数据库 中销毁具有给定名称的 对象存储。请注意,此方法只能在 升级事务 中调用。

    此方法同步修改在其上调用的 IDBDatabase 实例上的 objectStoreNames 属性。

    transaction = connection . transaction(scope [, mode [, options ] ])

    返回一个新的 事务,具有给定的 scope(可以是单个 对象存储 名称 或名称数组)、mode ("readonly" 或 "readwrite") 以及包括 durability ("default", "strict" 或 "relaxed") 的附加 options

    默认的 mode 为 "readonly",默认的 durability 为 "default"。

    connection . close()

    一旦所有正在运行的 事务 完成,即关闭 连接

    transaction(storeNames, mode, options) 方法步骤为

    1. 如果一个 活跃升级事务 与此 连接 关联,则 抛出 "InvalidStateError" DOMException

    2. 如果 此对象关闭挂起标志 为 true,则 抛出 "InvalidStateError" DOMException

    3. scopestoreNames 中的唯一字符串集合(如果是序列),否则为包含一个等于 storeNames 的字符串的集合。

    4. 如果 scope 中的任何字符串不是 已连接 数据库对象存储 的名称,则 抛出 "NotFoundError" DOMException

    5. 如果 scope 为空,则 抛出 "InvalidAccessError" DOMException

    6. 如果 mode 不为 "readonly" 或 "readwrite",则 抛出 一个 TypeError

    7. transaction 为一个新的 创建的 事务,具有此 连接modeoptionsdurability 成员,以及 scope 中命名的 对象存储 集合。

    8. transaction清理事件循环 设置为当前的 事件循环

    9. 返回一个代表 transactionIDBTransaction 对象。

    🚧 durability 选项是本版本新增的。它在 Chrome 82、Edge 82、Firefox 126 和 Safari 15 中得到支持。 🚧

    注意: 创建的 transaction 将遵循 生命周期 规则。

    close() 方法步骤为

    1. 运行 关闭数据库连接,使用此 连接

    注意: 连接 不会真正 关闭,直到所有未完成的 事务 完成。后续调用 close() 将不会有任何效果。

    onabort 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型abort

    onclose 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型close

    onerror 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型error

    onversionchange 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型versionchange

    4.5. IDBObjectStore 接口

    IDBObjectStore 接口代表一个 对象存储句柄

    [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 queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                        optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
      [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 = {});
      undefined deleteIndex(DOMString name);
    };
    
    dictionary IDBIndexParameters {
      boolean unique = false;
      boolean multiEntry = false;
    };
    
    dictionary IDBGetAllOptions {
      any query = null;
      [EnforceRange] unsigned long count;
      IDBCursorDirection direction = "next";
    };
    
    store . name

    返回存储的 名称

    store . name = newName

    将存储的 名称 更新为 newName

    如果未在 升级事务 中调用,则抛出 "InvalidStateError" DOMException

    store . keyPath

    返回存储的 键路径,如果无则返回 null。

    store . indexNames

    返回存储中索引的名称列表。

    store . transaction

    返回关联的 事务

    store . autoIncrement

    如果存储具有 键生成器,则返回 true,否则返回 false。

    name getter 的步骤是返回 thisname

    这是否与 object storename 相同?只要 transactionfinished,这就与关联的 object storename 相同。但一旦 transaction finished,此属性将不会反映后续 upgrade transaction 所做的更改。

    name setter 的步骤是

    1. namethe given value

    2. transactionthistransaction

    3. storethisobject store

    4. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    5. 如果 transaction 不是 upgrade transaction,则 throw 一个 "InvalidStateError" DOMException

    6. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    7. 如果 storename 等于 name,则终止这些步骤。

    8. 如果 storedatabase 中已存在一个 object store named name,则 throw 一个 "ConstraintError" DOMException

    9. storename 设置为 name

    10. thisname 设置为 name

    keyPath getter 的步骤是返回 thisobject storekey path,如果不存在则返回 null。根据 [WEBIDL]key path 会被转换为 DOMString(如果是一个字符串)或 sequence<DOMString>(如果是一个字符串列表)。

    注意: 返回的值不是创建 object store 时使用的同一实例。但是,如果此属性返回一个对象(特别是 Array),则每次检查时都会返回相同的对象实例。更改该对象的属性对 object store 没有影响。

    indexNames getter 的步骤是
    1. namesthisindex setindexesnameslist

    2. 返回 creating a sorted name list 使用 names 的结果(一个 DOMStringList)。

    这是否与 object storeindex names 列表相同?只要 transactionfinished,这就与关联的 object storeindex names 列表相同。但一旦 transaction finished,此属性将不会反映后续 upgrade transaction 所做的更改。

    transaction getter 的步骤是返回 thistransaction

    autoIncrement getter 的步骤是:如果 thisobject store 拥有 key generator 则返回 true,否则返回 false。

    以下方法如果在 read-only transaction 中调用,会 throw 一个 "ReadOnlyError" DOMException;如果在 transactionactive 时调用,则 throw 一个 "TransactionInactiveError" DOMException
    request = store . put(value [, key])
    request = store . add(value [, key])

    使用给定的 valuekeystore 中添加或更新 record

    如果 store 使用 in-line keys 且指定了 key,则会 throw 一个 "DataError" DOMException

    如果使用 put(),则会替换该 key 下的任何现有 record。如果使用 add(),且该 key 下已存在 record,则 request 将失败,并将 requesterror 设置为 "ConstraintError" DOMException

    如果成功,requestresult 将是 recordkey

    request = store . delete(query)

    删除 store 中与给定的 keyquery 中的 key range 匹配的 records

    如果成功,requestresult 将是 undefined

    request = store . clear()

    删除 store 中的所有 records

    如果成功,requestresult 将是 undefined

    put(value, key) 方法的步骤是返回运行 add or put 的结果,参数为 thisvaluekey 以及 no-overwrite flag false。

    add(value, key) 方法的步骤是返回运行 add or put 的结果,参数为 thisvaluekey 以及 no-overwrite flag true。

    add or put 使用 handlevaluekeyno-overwrite flag,请运行以下步骤:

    1. transactionhandletransaction

    2. storehandleobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. 如果 transactionread-only transaction,则 throw 一个 "ReadOnlyError" DOMException

    6. 如果 store 使用 in-line keys 且给定了 key,则 throw 一个 "DataError" DOMException

    7. 如果 store 使用 out-of-line keys 且没有 key generator,且未给定 key,则 throw 一个 "DataError" DOMException

    8. 如果给定了 key,则

      1. rconverting a value to a key 使用 key 的结果。重新抛出任何异常。

      2. 如果 r 是“invalid value”或“invalid type”,则 throw 一个 "DataError" DOMException

      3. keyr

    9. targetRealm 为用户代理定义的 Realm

    10. clonevaluetargetRealm 中于 transaction 期间的 clone。重新抛出任何异常。

      为什么要创建值的副本?值在存储时会被序列化。在此将其视为副本允许规范中的其他算法将其视为 ECMAScript 值,但如果行为差异不可观察,实现可以对其进行优化。
    11. 如果 store 使用 in-line keys,则

      1. kpk 为使用 clonestorekey path extracting a key from a value using a key path 的结果。重新抛出任何异常。

      2. 如果 kpk 无效,则 throw 一个 "DataError" DOMException

      3. 如果 kpk 不是失败(failure),令 keykpk

      4. 否则(kpk 为 failure)

        1. 如果 store 没有 key generator,则 throw 一个 "DataError" DOMException

        2. 如果使用 clonestorekey path 执行 check that a key could be injected into a value 返回 false,则 throw 一个 "DataError" DOMException

    12. operation 为运行 store a record into an object store 的算法,参数为 storeclonekeyno-overwrite flag

    13. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 handleoperation

    delete(query) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. 如果 transactionread-only transaction,则 throw 一个 "ReadOnlyError" DOMException

    6. rangeconverting a value to a key range 使用 query 和 true 的结果。重新抛出任何异常。

    7. operation 为运行 delete records from an object store 的算法,参数为 storerange

    8. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 thisoperation

    注意: query 参数可以是标识要删除的 recordskeykey range(一个 IDBKeyRange)。

    注意: 与其他接受 key 或 key range 的方法不同,此方法允许将 null 作为 key 传入。这是为了降低因小错误而清空整个 object store 的风险。

    clear() 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. 如果 transactionread-only transaction,则 throw 一个 "ReadOnlyError" DOMException

    6. operation 为运行 clear an object store 的算法,参数为 store

    7. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 thisoperation

    以下方法如果在 transactionactive 时调用,会 throw 一个 "TransactionInactiveError" DOMException
    request = store . get(query)

    检索与给定的 keyquery 中的 key range 匹配的第一个 recordvalue

    如果成功,requestresult 将是该 value;如果不存在匹配的 record,则为 undefined

    request = store . getKey(query)

    检索与给定的 keyquery 中的 key range 匹配的第一个 recordkey

    如果成功,requestresult 将是该 key;如果不存在匹配的 record,则为 undefined

    request = store . getAll(query [, count])
    request = store . getAll({query, count, direction})

    检索 query 中与给定的 keykey range 匹配的 recordsvalues(如果指定,最多为 count 个)。将 direction 选项设置为 "next" 以检索前 count 个值,或设置为 "prev" 以返回最后 count 个值。

    如果成功,requestresult 将是一个包含这些 valuesArray

    request = store . getAllKeys(query [, count])
    request = store . getAllKeys({query, count, direction})

    检索 query 中与给定的 keykey range 匹配的 recordskeys(如果指定,最多为 count 个)。将 direction 选项设置为 "next" 以检索前 count 个 key,或设置为 "prev" 以返回最后 count 个 key。

    如果成功,requestresult 将是一个包含这些 keysArray

    request = store . getAllRecords({query, count, direction})

    检索 recordskeysvalues

    query 选项指定要匹配的 keykey rangecount 选项限制匹配的记录数。将 direction 选项设置为 "next" 以检索前 count 个记录,或设置为 "prev" 以返回最后 count 个记录。

    如果成功,requestresult 将是一个 Array,其中的每个成员都是一个 IDBRecord

    request = store . count(query)

    检索与给定的 keyquery 中的 key range 匹配的 records 的数量。

    如果成功,requestresult 将是该计数。

    get(query) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. rangeconverting a value to a key range 使用 query 和 true 的结果。重新抛出任何异常。

    6. operation 为运行 retrieve a value from an object store 的算法,参数为 the current Realm recordstorerange

    7. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 thisoperation

    注意: query 参数可以是标识要检索的 record 值的 keykey range(一个 IDBKeyRange)。如果指定了范围,该方法会检索该范围内第一个存在的值。

    注意: 如果具有给定 key 的记录不存在,则此方法产生的结果与记录存在但值为 undefined 时产生的结果相同。如果您需要区分这两种情况,可以使用具有相同 key 的 openCursor()。如果记录存在,这将返回一个值为 undefined 的游标;如果不存在此类记录,则不返回游标。

    getKey(query) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. rangeconverting a value to a key range 使用 query 和 true 的结果。重新抛出任何异常。

    6. operation 为运行 retrieve a key from an object store 的算法,参数为 storerange

    7. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 thisoperation

    注意: query 参数可以是标识要检索的 record key 的 keykey range(一个 IDBKeyRange)。如果指定了范围,该方法会检索该范围内第一个存在的 key。

    getAll(queryOrOptions, count) 方法的步骤是

    1. 返回 creating a request to retrieve multiple items 的结果,参数为 the current Realm recordthis、"value"、queryOrOptions 以及(如果给定的话)count。重新抛出任何异常。

    getAllKeys(queryOrOptions, count) 方法的步骤是

    1. 返回 creating a request to retrieve multiple items 的结果,参数为 the current Realm recordthis、"key"、queryOrOptions 以及(如果给定的话)count。重新抛出任何异常。

    getAllRecords(options) 方法的步骤是

    1. 返回 creating a request to retrieve multiple items 的结果,参数为 the current Realm recordthis、"record" 和 options。重新抛出任何异常。

    count(query) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. rangeconverting a value to a key range 使用 query 的结果。重新抛出任何异常。

    6. operation 为运行 count the records in a range 的算法,参数为 storerange

    7. 返回运行 asynchronously execute a request 的结果(一个 IDBRequest),参数为 thisoperation

    注意: query 参数可以是标识要计数的 recordskeykey range(一个 IDBKeyRange)。如果为 null 或未给定,则使用 unbounded key range

    以下方法如果在 transactionactive 时调用,会 throw 一个 "TransactionInactiveError" DOMException
    request = store . openCursor([query [, direction = "next"]])

    在一个 cursor 上开启一个游标,覆盖与 query 匹配的 records,并按 direction 排序。如果 query 为 null,则 store 中的所有 records 都会被匹配。

    如果成功,requestresult 将是一个指向第一个匹配的 recordIDBCursorWithValue;如果没有匹配的 records,则为 null。

    request = store . openKeyCursor([query [, direction = "next"]])

    开启一个 cursor,其 key only flag 设置为 true,覆盖与 query 匹配的 records,并按 direction 排序。如果 query 为 null,则 store 中的所有 records 都会被匹配。

    如果成功,requestresult 将是一个指向第一个匹配的 recordIDBCursor;如果没有匹配的 records,则为 null。

    openCursor(query, direction) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. rangeconverting a value to a key range 使用 query 的结果。重新抛出任何异常。

    6. cursor 为一个新的 cursor,其 source handle 设置为 thisposition 为 undefined,direction 设置为 directiongot value flag 设置为 false,keyvalue 为 undefined,range 设置为 range,且 key only flag 设置为 false。

    7. operation 为运行 iterate a cursor 的算法,参数为 the current Realm recordcursor

    8. request 为运行 asynchronously execute a request 的结果,参数为 thisoperation

    9. cursorrequest 设置为 request

    10. 返回 request

    注意: query 参数可以是标识用作 cursorrangekeykey range(一个 IDBKeyRange)。如果为 null 或未给定,则使用 unbounded key range

    openKeyCursor(query, direction) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    5. rangeconverting a value to a key range 使用 query 的结果。重新抛出任何异常。

    6. cursor 为一个新的 cursor,其 source handle 设置为 thisposition 为 undefined,direction 设置为 directiongot value flag 设置为 false,keyvalue 为 undefined,range 设置为 range,且 key only flag 设置为 true。

    7. operation 为运行 iterate a cursor 的算法,参数为 the current Realm recordcursor

    8. request 为运行 asynchronously execute a request 的结果,参数为 thisoperation

    9. cursorrequest 设置为 request

    10. 返回 request

    注意: query 参数可以是标识用作 cursorrangekeykey range(一个 IDBKeyRange)。如果为 null 或未给定,则使用 unbounded key range

    index = store . index(name)

    返回 store 中名为 nameindexIDBIndex

    index = store . createIndex(name, keyPath [, options])

    store 中创建一个具有给定 namekeyPathoptions 的新 index,并返回一个新 IDBIndex。如果 keyPathoptions 定义的约束无法通过 store 中已有的数据满足,则 upgrade transactionabort 并抛出 "ConstraintError" DOMException

    如果未在 upgrade transaction 中调用,则 throw 一个 "InvalidStateError" DOMException

    store . deleteIndex(name)

    删除 store 中具有给定 nameindex

    如果未在 upgrade transaction 中调用,则 throw 一个 "InvalidStateError" DOMException

    createIndex(name, keyPath, options) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 transaction 不是 upgrade transaction,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    5. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    6. 如果 store 中已存在一个 named nameindex,则 throw 一个 "ConstraintError" DOMException

    7. 如果 keyPath 不是 valid key path,则 throw 一个 "SyntaxError" DOMException

    8. uniqueoptionsunique 成员。

    9. multiEntryoptionsmultiEntry 成员。

    10. 如果 keyPath 是序列且 multiEntry 为 true,则 throw 一个 "InvalidAccessError" DOMException

    11. indexstore 中的一个新 index。将 indexname 设置为 namekey path 设置为 keyPathunique flag 设置为 unique,以及 multiEntry flag 设置为 multiEntry

    12. index 添加到 thisindex set

    13. 返回一个与 indexthis 关联的新 index handle

    此方法在 object store 中创建并返回一个具有给定名称的新 index。注意,此方法必须仅在 upgrade transaction 中调用。

    请求创建的索引可以包含对该索引 referenced object store 中允许数据的约束,例如要求索引 key path 所引用的值具有唯一性。如果 referenced object store 中已包含违反这些约束的数据,这不得导致 createIndex() 的实现抛出异常或影响其返回值。实现仍必须创建并返回一个 IDBIndex 对象,并且实现必须 queue a database task 来中止用于 createIndex() 调用的 upgrade transaction

    此方法同步修改调用它的 IDBObjectStore 实例上的 indexNames 属性。尽管此方法不返回 IDBRequest 对象,但索引创建本身在 upgrade transaction 中作为异步请求处理。

    在某些实现中,createIndex() 方法返回后,实现可能会异步遇到索引创建问题。例如,在有关新创建索引的元数据排队等待异步插入数据库的实现中,或者实现因配额原因需要询问用户权限的情况下。此类实现仍必须创建并返回一个 IDBIndex 对象,并且一旦实现确定索引创建失败,它必须使用适当的错误运行 abort a transaction 的步骤。例如,如果由于配额原因导致创建 index 失败,则必须使用 QuotaExceededError 作为错误;如果由于 unique flag 约束导致无法创建索引,则必须使用 "ConstraintError" DOMException 作为错误。

    索引的异步创建在以下示例中是可观察到的

    const request1 = objectStore.put({name: "betty"}, 1);
    const request2 = objectStore.put({name: "betty"}, 2);
    const index = objectStore.createIndex("by_name", "name", {unique: true});
    

    在调用 createIndex() 的位置,两个 requests 均未执行。当第二个请求执行时,创建了一个重复名称。由于索引创建被视为异步 request,索引的 uniqueness constraint 不会导致第二个 request 失败。相反,当索引创建且约束失败时,transaction 将被 aborted

    index(name) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 transactionstatefinished,则 throw 一个 "InvalidStateError" DOMException

    5. indexthisindex setnamed nameindex(如果存在),否则 throw 一个 "NotFoundError" DOMException

    6. 返回一个与 indexthis 关联的 index handle

    注意: 在同一 IDBObjectStore 实例上使用相同名称调用此方法的每次调用都会返回相同的 IDBIndex 实例。

    注意: 返回的 IDBIndex 实例特定于此 IDBObjectStore 实例。如果在不同的 IDBObjectStore 实例上使用相同名称调用此方法,则会返回不同的 IDBIndex 实例。

    deleteIndex(name) 方法的步骤是

    1. transactionthistransaction

    2. storethisobject store

    3. 如果 transaction 不是 upgrade transaction,则 throw 一个 "InvalidStateError" DOMException

    4. 如果 store 已被删除,则 throw 一个 "InvalidStateError" DOMException

    5. 如果 transactionstate 不是 active,则 throw 一个 "TransactionInactiveError" DOMException

    6. indexstorenamed nameindex(如果存在),否则 throw 一个 "NotFoundError" DOMException

    7. thisindex set 中移除 index

    8. 销毁 index

    此方法销毁 object store 中具有给定名称的 index。注意,此方法必须仅在 upgrade transaction 中调用。

    此方法同步修改调用它的 IDBObjectStore 实例上的 indexNames 属性。尽管此方法不返回 IDBRequest 对象,但索引销毁本身在 upgrade transaction 中作为异步请求处理。

    4.6. IDBIndex 接口

    IDBIndex 接口表示一个 index handle

    [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 queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                        optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
      [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");
    };
    
    index . name

    返回索引的 name

    index . name = newName

    将 store 的 name 更新为 newName

    如果未在 upgrade transaction 中调用,则 throw 一个 "InvalidStateError" DOMException

    index . objectStore

    返回该索引所属的 IDBObjectStore

    index . keyPath

    返回该索引的 key path

    index . multiEntry

    如果索引的 multiEntry flag 为 true,则返回 true。

    index . unique

    如果索引的 unique flag 为 true,则返回 true。

    name getter 的步骤是返回 thisname

    这是否与 indexname 相同?只要 transactionfinished,这就与关联的 indexname 相同。但一旦 transaction finished,此属性将不会反映后续 upgrade transaction 所做的更改。

    name setter 的步骤是

    1. namethe given value

    2. transactionthistransaction

    3. indexthisindex

    4. 如果 transaction 不是 升级事务,则 抛出 "InvalidStateError" DOMException

    5. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    6. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    7. 如果 index名称 等于 name,则终止这些步骤。

    8. 如果 index对象仓库 中已经存在一个 命名为 name索引,则 抛出 "ConstraintError" DOMException

    9. index名称 设置为 name

    10. this名称 设置为 name

    objectStore 获取器步骤是返回 this对象仓库句柄

    keyPath 获取器步骤是返回 this索引键路径。根据 [WEBIDL],该 键路径 将转换为 DOMString(如果是一个字符串)或 sequence<DOMString>(如果是一个字符串序列)。

    注意: 返回的值并非创建 索引 时使用的同一个实例。然而,如果该属性返回一个对象(特别是 Array),它每次被检查时都会返回同一个对象实例。更改该对象的属性不会对 索引 产生影响。

    multiEntry 获取器步骤是返回 this索引多重条目标志

    unique 获取器步骤是返回 this索引唯一性标志

    如果在 事务活跃 时调用,以下方法会抛出 "TransactionInactiveError" DOMException
    request = index . get(query)

    检索 query 中给定的 键范围 匹配的第一个 记录

    如果成功,requestresult 将为该 ,如果没有匹配的 记录,则为 undefined

    request = index . getKey(query)

    检索 query 中给定的 键范围 匹配的第一个 记录

    如果成功,requestresult 将为该 ,如果没有匹配的 记录,则为 undefined

    request = index . getAll(query [, count])
    request = index . getAll({query, count, direction})

    检索 query 中给定的 键范围 匹配的 记录(如果给定了 count,则最多检索 count 条)。将 direction 选项设置为 "next" 以检索前 count 个值,设置为 "prev" 以返回最后 count 个值。将 direction 选项设置为 "nextunique" 或 "prevunique",可在检索到具有重复索引键的第一个记录后,排除具有相同索引键的记录。

    如果成功,requestresult 将为包含这些 Array

    request = index . getAllKeys(query [, count])
    request = index . getAllKeys({query, count, direction})

    检索 query 中给定的 键范围 匹配的 记录(如果给定了 count,则最多检索 count 条)。将 direction 选项设置为 "next" 以检索前 count 个键,设置为 "prev" 以返回最后 count 个键。将 direction 选项设置为 "nextunique" 或 "prevunique",可在检索到具有重复索引键的第一个记录后,排除具有相同索引键的记录。

    如果成功,requestresult 将为包含这些 Array

    request = index . getAllRecords({query, count, direction})

    检索 记录 以及索引

    query 选项指定要匹配的 键范围count 选项限制匹配记录的数量。将 direction 选项设置为 "next" 以检索前 count 条记录,设置为 "prev" 以返回最后 count 条记录。将 direction 选项设置为 "nextunique" 或 "prevunique",可在检索到具有重复索引键的第一个记录后,排除具有相同索引键的记录。

    如果成功,requestresult 将为一个 Array,其每个成员都是一个 IDBRecord。使用 IDBRecord 的 key 获取记录的索引 。使用 IDBRecord 的 primaryKey 获取记录的

    request = index . count(query)

    检索 query 中给定的 键范围 匹配的 记录 的数量。

    如果成功,requestresult 将为计数值。

    get(query) 方法步骤是

    1. transactionthis事务

    2. indexthis索引

    3. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    5. range将值转换为键范围(使用 query 和 true)的结果。重新抛出任何异常。

    6. operation 为运行 从索引中检索引用值 算法,该算法使用 当前 Realm 记录indexrange

    7. 返回运行 异步执行请求 的结果(一个 IDBRequest),该操作使用 thisoperation

    注意: query 参数可以是标识要检索的 引用值键范围(一个 IDBKeyRange)。如果指定了范围,该方法会检索该范围内第一个存在的记录。

    注意: 当给定键的记录不存在时,此方法产生的结果与记录存在但值为 undefined 时相同。如果您需要区分这两种情况,可以使用带有相同键的 openCursor()。如果记录存在,这将返回一个值为 undefined 的游标;如果不存在此类记录,则不返回任何游标。

    getKey(query) 方法步骤是

    1. transactionthis事务

    2. indexthis索引

    3. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    5. range将值转换为键范围(使用 query 和 true)的结果。重新抛出任何异常。

    6. operation 为运行 从索引中检索值 算法,该算法使用 indexrange

    7. 返回运行 异步执行请求 的结果(一个 IDBRequest),该操作使用 thisoperation

    注意: query 参数可以是标识要检索的 记录 键的 键范围(一个 IDBKeyRange)。如果指定了范围,该方法会检索该范围内第一个存在的键。

    getAll(queryOrOptions, count) 方法步骤是

    1. 返回运行 创建检索多个项目的请求 的结果,该算法使用 当前 Realm 记录this、"value"、queryOrOptions 和(如果给定)count。重新抛出任何异常。

    getAllKeys(queryOrOptions, count) 方法步骤是

    1. 返回运行 创建检索多个项目的请求 的结果,该算法使用 当前 Realm 记录this、"key"、queryOrOptions 和(如果给定)count。重新抛出任何异常。

    getAllRecords(options) 方法步骤是

    1. 返回运行 创建检索多个项目的请求 的结果,该算法使用 当前 Realm 记录this、"record" 和 options。重新抛出任何异常。

    count(query) 方法步骤是

    1. transactionthis事务

    2. indexthis索引

    3. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    5. range将值转换为键范围(使用 query)的结果。重新抛出任何异常。

    6. operation 为运行 计算范围内记录数 算法,该算法使用 indexrange

    7. 返回运行 异步执行请求 的结果(一个 IDBRequest),该操作使用 thisoperation

    注意: query 参数可以是标识要计算的 记录键范围(一个 IDBKeyRange)。如果为 null 或未给出,则使用 无界键范围

    如果在 事务活跃 时调用,以下方法会抛出 "TransactionInactiveError" DOMException
    request = index . openCursor([query [, direction = "next"]])

    在与 query 匹配的 记录 上打开一个按 direction 排序的 游标。如果 query 为 null,则匹配 index 中的所有 记录

    如果成功,requestresult 将为 IDBCursorWithValue,若没有匹配的 记录,则为 null。

    request = index . openKeyCursor([query [, direction = "next"]])

    在与 query 匹配的 记录 上打开一个按 direction 排序且 仅键标志 设置为 true 的 游标。如果 query 为 null,则匹配 index 中的所有 记录

    如果成功,requestresult 将为 IDBCursor,若没有匹配的 记录,则为 null。

    openCursor(query, direction) 方法步骤是

    1. transactionthis事务

    2. indexthis索引

    3. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    5. range将值转换为键范围(使用 query)的结果。重新抛出任何异常。

    6. cursor 为一个新的 游标,其 源句柄 设置为 this位置 为 undefined,方向 设置为 direction获取值标志 设置为 false, 为 undefined,范围 设置为 range仅键标志 设置为 false。

    7. operation 为运行 遍历游标 算法,该算法使用 当前 Realm 记录cursor

    8. request 为运行 异步执行请求 的结果,该操作使用 thisoperation

    9. cursor请求 设置为 request

    10. 返回 request

    注意: query 参数可以是标识作为 游标范围键范围(一个 IDBKeyRange)。如果为 null 或未给出,则使用 无界键范围

    openKeyCursor(query, direction) 方法步骤是

    1. transactionthis事务

    2. indexthis索引

    3. 如果 indexindex对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    5. range将值转换为键范围(使用 query)的结果。重新抛出任何异常。

    6. cursor 为一个新的 游标,其 源句柄 设置为 this位置 为 undefined,方向 设置为 direction获取值标志 设置为 false, 为 undefined,范围 设置为 range仅键标志 设置为 true。

    7. operation 为运行 遍历游标 算法,该算法使用 当前 Realm 记录cursor

    8. request 为运行 异步执行请求 的结果,该操作使用 thisoperation

    9. cursor请求 设置为 request

    10. 返回 request

    注意: query 参数可以是标识作为 游标范围键范围(一个 IDBKeyRange)。如果为 null 或未给出,则使用 无界键范围

    4.7. IDBKeyRange 接口

    IDBKeyRange 接口表示一个 键范围

    [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);
    };
    
    range . lower

    返回范围的 下界,如果没有则为 undefined

    range . upper

    返回范围的 上界,如果没有则为 undefined

    range . lowerOpen

    返回范围的 下界开启标志

    range . upperOpen

    返回范围的 上界开启标志

    lower 获取器步骤是返回 将键转换为值(使用 this下界,如果其不为 null,否则为 undefined)的结果。

    upper 获取器步骤是返回 将键转换为值(使用 this上界,如果其不为 null,否则为 undefined)的结果。

    lowerOpen 获取器步骤是返回 this下界开启标志

    upperOpen 获取器步骤是返回 this上界开启标志

    range = IDBKeyRange . only(key)

    返回一个新的 IDBKeyRange,仅覆盖 key

    range = IDBKeyRange . lowerBound(key [, open = false])

    返回一个新的 IDBKeyRange,从 key 开始且没有上界。如果 open 为 true,则 key 不包含在范围内。

    range = IDBKeyRange . upperBound(key [, open = false])

    返回一个新的 IDBKeyRange,没有下界且以 key 结束。如果 open 为 true,则 key 不包含在范围内。

    range = IDBKeyRange . bound(lower, upper [, lowerOpen = false [, upperOpen = false]])

    返回一个新的 IDBKeyRange,覆盖从 lowerupper 的范围。如果 lowerOpen 为 true,则 lower 不包含在范围内。如果 upperOpen 为 true,则 upper 不包含在范围内。

    only(value) 方法步骤是

    1. key将值转换为键(使用 value)的结果。重新抛出任何异常。

    2. 如果 key 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    3. 创建并返回一个仅 包含 key 的新 键范围

    lowerBound(lower, open) 方法步骤是

    1. lowerKey将值转换为键(使用 lower)的结果。重新抛出任何异常。

    2. 如果 lowerKey 无效,则 抛出 "DataError" DOMException

    3. 创建并返回一个新 键范围,其 下界 设置为 lowerKey下界开启标志 设置为 open上界 设置为 null,上界开启标志 设置为 true。

    upperBound(upper, open) 方法步骤是

    1. upperKey将值转换为键(使用 upper)的结果。重新抛出任何异常。

    2. 如果 upperKey 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    3. 创建并返回一个新 键范围,其 下界 设置为 null,下界开启标志 设置为 true,上界 设置为 upperKey上界开启标志 设置为 open

    bound(lower, upper, lowerOpen, upperOpen) 方法步骤是

    1. lowerKey将值转换为键(使用 lower)的结果。重新抛出任何异常。

    2. 如果 lowerKey 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    3. upperKey将值转换为键(使用 upper)的结果。重新抛出任何异常。

    4. 如果 upperKey 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    5. 如果 lowerKey 大于 upperKey,则 抛出 "DataError" DOMException

    6. 创建并返回一个新 键范围,其 下界 设置为 lowerKey下界开启标志 设置为 lowerOpen上界 设置为 upperKey上界开启标志 设置为 upperOpen

    range . includes(key)

    如果 key 包含在范围内,则返回 true,否则返回 false。

    includes(key) 方法步骤是

    1. k将值转换为键(使用 key)的结果。重新抛出任何异常。

    2. 如果 k 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    3. 如果 k 处于 本范围内,则返回 true,否则返回 false。

    4.8. IDBRecord 接口

    IDBRecord 接口表示一个 记录快照

    [Exposed=(Window,Worker)]
    interface IDBRecord {
      readonly attribute any key;
      readonly attribute any primaryKey;
      readonly attribute any value;
    };
    
    record . key

    返回记录的

    record . primaryKey

    如果记录是从 索引 中检索的,则返回记录在该索引的 引用对象仓库 中的键。

    如果记录是从 对象仓库 中检索的,则返回记录的 ,该键与 record.key 相同。

    record . value

    返回记录的

    key 获取器步骤是返回 将键转换为值(使用 this)的结果。

    primaryKey 获取器步骤是返回 将键转换为值(使用 this主键)的结果。

    value 获取器步骤是返回 this

    4.9. IDBCursor 接口

    游标 对象实现 IDBCursor 接口。对于给定的 游标,始终只有一个代表它的 IDBCursor 实例。同时可以使用的游标数量没有限制。

    [Exposed=(Window,Worker)]
    interface IDBCursor {
      readonly attribute (IDBObjectStore or IDBIndex) source;
      readonly attribute IDBCursorDirection direction;
      readonly attribute any key;
      readonly attribute any primaryKey;
      [SameObject] readonly attribute IDBRequest request;
    
      undefined advance([EnforceRange] unsigned long count);
      undefined continue(optional any key);
      undefined continuePrimaryKey(any key, any primaryKey);
    
      [NewObject] IDBRequest update(any value);
      [NewObject] IDBRequest delete();
    };
    
    enum IDBCursorDirection {
      "next",
      "nextunique",
      "prev",
      "prevunique"
    };
    
    cursor . source

    返回打开该游标的 IDBObjectStoreIDBIndex

    cursor . direction

    返回游标的 方向("next"、"nextunique"、"prev" 或 "prevunique")。

    cursor . key

    返回游标的 。如果游标正在推进或已结束,则抛出 "InvalidStateError" DOMException

    cursor . primaryKey

    返回游标的 有效键。如果游标正在推进或已结束,则抛出 "InvalidStateError" DOMException

    cursor . request

    返回用于获取此游标的 请求

    source 获取器步骤是返回 this源句柄

    注意: source 属性从不返回 null 或抛出异常,即使游标当前正在被遍历、已遍历至末尾,或者其 事务活跃

    direction 获取器步骤是返回 this方向

    key 获取器步骤是返回 将键转换为值(使用游标当前的 )的结果。

    注意: 如果 key 返回一个对象(例如 DateArray),它每次被检查时都会返回同一个对象实例,直到游标的 发生改变。这意味着如果对象被修改,任何检查游标值的人都会看到这些修改。然而,修改此类对象不会修改数据库的内容。

    primaryKey 获取器步骤是返回 将键转换为值(使用游标当前的 有效键)的结果。

    注意: 如果 primaryKey 返回一个对象(例如 DateArray),它每次被检查时都会返回同一个对象实例,直到游标的 有效键 发生改变。这意味着如果对象被修改,任何检查游标值的人都会看到这些修改。然而,修改此类对象不会修改数据库的内容。

    request 获取器步骤是返回 this请求

    🚧 request 属性在本版本中新增。它在 Chrome 76、Edge 79、Firefox 77 和 Safari 15 中得到支持。🚧
    以下方法用于推进 游标。一旦游标推进,将在打开游标时返回的同一个 IDBRequest 上触发一个 success 事件。如果范围内有 记录result 将为同一个游标,否则为 undefined

    如果游标正在推进时调用,将抛出 "InvalidStateError" DOMException

    如果在 事务活跃 时调用,以下方法会抛出 "TransactionInactiveError" DOMException

    cursor . advance(count)

    将游标向前推进范围内的下 count记录

    cursor . continue()

    将游标向前推进范围内的下一条 记录

    cursor . continue(key)

    将游标向前推进范围内匹配或之后 key 的下一条 记录

    cursor . continuePrimaryKey(key, primaryKey)

    将游标向前推进范围内匹配或之后 keyprimaryKey 的下一条 记录。如果 source 不是 索引,则抛出 "InvalidAccessError" DOMException

    advance(count) 方法步骤是

    1. 如果 count 为 0,则 抛出 TypeError

    2. transactionthis事务

    3. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    4. 如果 thissource有效对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    5. 如果 this获取值标志 为 false(表示游标正在被遍历或已遍历至末尾),则 抛出 "InvalidStateError" DOMException

    6. this获取值标志 设置为 false。

    7. requestthis请求

    8. request处理标志 设置为 false。

    9. request完成标志 设置为 false。

    10. operation 为运行 遍历游标 算法,该算法使用 当前 Realm 记录thiscount

    11. 运行 异步执行请求 算法,该算法使用 this源句柄operationrequest

    注意: 在新的游标数据加载之前多次调用此方法(例如在同一个 onsuccess 处理程序中两次调用 advance()),会导致第二次调用时抛出 "InvalidStateError" DOMException,因为游标的 获取值标志 已被设置为 false。

    continue(key) 方法步骤是

    1. transactionthis事务

    2. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    3. 如果 thissource有效对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 this获取值标志 为 false(表示游标正在被遍历或已遍历至末尾),则 抛出 "InvalidStateError" DOMException

    5. 如果给定了 key,则

      1. r将值转换为键(使用 key)的结果。重新抛出任何异常。

      2. 如果 r 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

      3. keyr

      4. 如果 key 小于等于 this位置,且 this方向 是 "next" 或 "nextunique",则 抛出 "DataError" DOMException

      5. 如果 key 大于等于 this位置,且 this方向 是 "prev" 或 "prevunique",则 抛出 "DataError" DOMException

    6. this获取值标志 设置为 false。

    7. requestthis请求

    8. request处理标志 设置为 false。

    9. request完成标志 设置为 false。

    10. operation 为运行 遍历游标 算法,该算法使用 当前 Realm 记录thiskey(如果给定)。

    11. 运行 异步执行请求 算法,该算法使用 this源句柄operationrequest

    注意: 在新的游标数据加载之前多次调用此方法(例如在同一个 onsuccess 处理程序中两次调用 continue()),会导致第二次调用时抛出 "InvalidStateError" DOMException,因为游标的 获取值标志 已被设置为 false。

    continuePrimaryKey(key, primaryKey) 方法步骤是

    1. transactionthis事务

    2. 如果 transaction状态 不是 活跃,则 抛出 "TransactionInactiveError" DOMException

    3. 如果 thissource有效对象仓库 已被删除,则 抛出 "InvalidStateError" DOMException

    4. 如果 thissource 不是 索引,则 抛出 "InvalidAccessError" DOMException

    5. 如果 this方向 不是 "next" 或 "prev",则 抛出 "InvalidAccessError" DOMException

    6. 如果 this获取值标志 为 false(表示游标正在被遍历或已遍历至末尾),则 抛出 "InvalidStateError" DOMException

    7. r将值转换为键(使用 key)的结果。重新抛出任何异常。

    8. 如果 r 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    9. keyr

    10. r将值转换为键(使用 primaryKey)的结果。重新抛出任何异常。

    11. 如果 r 是 "invalid value" 或 "invalid type",则 抛出 "DataError" DOMException

    12. primaryKeyr

    13. 如果 key 小于 this位置,且 this方向 是 "next",则 抛出 "DataError" DOMException

    14. 如果 key 大于 位置 方向 为 "prev",则 抛出 "DataError" DOMException

    15. 如果 key 等于 位置,且 primaryKey 小于等于 对象仓库位置,且 方向 为 "next",则 抛出 "DataError" DOMException

    16. 如果 key 等于 位置,且 primaryKey 大于等于 对象仓库位置,且 方向 为 "prev",则 抛出 "DataError" DOMException

    17. 获取值标志 设置为 false。

    18. request 请求

    19. request处理标志 设置为 false。

    20. request完成标志 设置为 false。

    21. operation 为运行 遍历游标 的算法,包含 当前领域记录keyprimaryKey

    22. 使用 源句柄operationrequest 运行 异步执行请求

    注意: 在新的游标数据加载之前多次调用此方法——例如,在同一个 onsuccess 处理程序中两次调用 continuePrimaryKey()——会导致第二次调用时抛出 "InvalidStateError" DOMException,因为游标的 获取值标志 已被设置为 false。

    如果以下方法在 只读事务 中被调用,则抛出 "ReadOnlyError" DOMException;如果调用时 事务活跃,则抛出 "TransactionInactiveError" DOMException
    request = cursor . update(value)

    使用新值更新游标指向的 记录

    如果 有效对象仓库 使用 内联键 会发生改变,则抛出 "DataError" DOMException

    如果成功,requestresult 将是该 记录

    request = cursor . delete()

    删除游标指向的 记录

    如果成功,requestresult 将为 undefined

    update(value) 方法的步骤如下

    1. transaction 事务

    2. 如果 transaction状态活跃,则 抛出 "TransactionInactiveError" DOMException

    3. 如果 transaction只读事务抛出 "ReadOnlyError" DOMException

    4. 如果 有效对象仓库 已被删除,抛出 "InvalidStateError" DOMException

    5. 如果 获取值标志 为 false(表示游标正在遍历或已遍历完),抛出 "InvalidStateError" DOMException

    6. 如果 仅键标志 为 true,抛出 "InvalidStateError" DOMException

    7. targetRealm 为用户代理定义的 领域 (Realm)

    8. clonevaluetargetRealmtransaction 期间的 克隆。重新抛出任何异常。

      为什么要创建值的副本?值在存储时会被序列化。在此将其视为副本允许规范中的其他算法将其视为 ECMAScript 值,但如果行为差异不可观察,实现可以对其进行优化。
    9. 如果 有效对象仓库 使用 内联键,则

      1. kpk 为使用 从值中使用键路径提取键 的算法处理 clone 有效对象仓库键路径 的结果。重新抛出任何异常。

      2. 如果 kpk 为失败、无效或不 等于 有效键抛出 "DataError" DOMException

    10. operation 为运行 将记录存入对象仓库 的算法,包含 有效对象仓库clone 有效键 和 false。

    11. 返回使用 operation 运行 异步执行请求 的结果(一个 IDBRequest)。

    注意: 将记录存入对象仓库 的结果是:如果该记录在游标移动到它之后被删除,则会创建一个新记录。

    delete() 方法的步骤如下

    1. transaction 事务

    2. 如果 transaction状态活跃,则 抛出 "TransactionInactiveError" DOMException

    3. 如果 transaction只读事务抛出 "ReadOnlyError" DOMException

    4. 如果 有效对象仓库 已被删除,抛出 "InvalidStateError" DOMException

    5. 如果 获取值标志 为 false(表示游标正在遍历或已遍历完),抛出 "InvalidStateError" DOMException

    6. 如果 仅键标志 为 true,抛出 "InvalidStateError" DOMException

    7. operation 为运行 从对象仓库中删除记录 的算法,包含 有效对象仓库 有效键

    8. 返回使用 operation 运行 异步执行请求 的结果(一个 IDBRequest)。

    仅键标志 设置为 false 的 游标 同时实现了 IDBCursorWithValue 接口。

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

    返回 游标 的当前

    value 获取器的步骤是返回 的当前

    注意: 如果 value 返回一个对象,每次检查它时都会返回相同的对象实例,直到游标的 发生改变。这意味着如果该对象被修改,任何检查游标值的人都会看到这些修改。但是,修改此类对象不会修改数据库的内容。

    4.10. IDBTransaction 接口

    事务 对象实现以下接口

    [Exposed=(Window,Worker)]
    interface IDBTransaction : EventTarget {
      readonly attribute DOMStringList objectStoreNames;
      readonly attribute IDBTransactionMode mode;
      readonly attribute IDBTransactionDurability durability;
      [SameObject] readonly attribute IDBDatabase db;
      readonly attribute DOMException? error;
    
      IDBObjectStore objectStore(DOMString name);
      undefined commit();
      undefined abort();
    
      // Event handlers:
      attribute EventHandler onabort;
      attribute EventHandler oncomplete;
      attribute EventHandler onerror;
    };
    
    enum IDBTransactionMode {
      "readonly",
      "readwrite",
      "versionchange"
    };
    
    transaction . objectStoreNames

    返回事务 范围对象仓库 的名称列表。对于 升级事务,这是 数据库 中的所有对象仓库。

    transaction . mode

    返回创建该事务时所使用的 模式("readonly" 或 "readwrite"),或者对于 升级事务,返回 "versionchange"。

    transaction . durability

    返回创建该事务时所使用的 持久性提示("strict"、"relaxed" 或 "default")。

    transaction . db

    返回该事务的 连接

    transaction . error

    如果事务被 终止,则返回提供原因的错误(一个 DOMException)。

    objectStoreNames 获取器的步骤如下

    1. names 范围对象仓库名称 列表

    2. 返回使用 names 创建排序名称列表 的结果(一个 DOMStringList)。

    注意: 此属性返回的每个列表的内容不会改变,但在 升级事务 期间对该属性的后续调用可能会返回不同内容的列表,因为 对象仓库 会被创建和删除。

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

    durability 获取器的步骤是返回 持久性提示

    🚧 durability 属性是本版本新增的。它在 Chrome 82、Edge 82、Firefox 126 和 Safari 15 中受支持。 🚧

    db 获取器的步骤是返回 连接 所关联的 数据库

    error 获取器的步骤是返回 错误,若无则返回 null。

    注意: 如果此 事务 是由于失败的 请求 而终止的,则该错误将与该 请求错误 相同。如果此 事务 是由于事件处理程序中的未捕获异常而终止的,则错误将是一个 "AbortError" DOMException。如果 事务 是由于提交过程中的错误而终止的,它将反映失败的原因(例如 QuotaExceededError,或 "ConstraintError" 或 "UnknownError" DOMException)。

    transaction . objectStore(name)

    返回 事务 范围 内的一个 IDBObjectStore

    transaction . abort()

    终止事务。所有待处理的 请求 都将失败并抛出 "AbortError" DOMException,所有对数据库所做的更改都将被撤销。

    transaction . commit()

    尝试提交事务。所有待处理的 请求 都将被允许完成,但不会接受任何新的请求。此方法可用于强制事务快速结束,而无需在尝试正常提交之前等待待处理请求触发 success 事件。

    如果待处理请求失败(例如由于约束错误),事务将会终止。成功请求的 success 事件仍会触发,但在事件处理程序中抛出异常不会导致事务终止。同样,失败请求的 error 事件仍会触发,但调用 preventDefault() 将无法阻止事务终止。

    objectStore(name) 方法的步骤如下

    1. 如果 状态已完成,则 抛出 "InvalidStateError" DOMException

    2. store 范围名为 name对象仓库;如果不存在,则 抛出 "NotFoundError" DOMException

    3. 返回与 store 关联的 对象仓库句柄

    注意: 在同一个 IDBTransaction 实例上使用相同名称调用此方法,每次都会返回同一个 IDBObjectStore 实例。

    注意: 返回的 IDBObjectStore 实例特定于此 IDBTransaction。如果此方法在不同的 IDBTransaction 上调用,则会返回不同的 IDBObjectStore 实例。

    abort() 方法的步骤如下

    1. 如果 状态正在提交已完成,则 抛出 "InvalidStateError" DOMException

    2. 使用 和 null 运行 终止事务

    commit() 方法的步骤如下

    1. 如果 状态活跃,则 抛出 "InvalidStateError" DOMException

    2. 使用 运行 提交事务

    🚧 commit() 方法是本版本新增的。它在 Chrome 76、Edge 79、Firefox 74 和 Safari 15 中受支持。 🚧

    注意: 通常没有必要在 事务 上调用 commit()。当所有未完成的请求都已满足且没有发出新请求时,事务将自动提交。此调用可用于在不等待分发来自未完成 请求 的事件的情况下启动 提交 过程。

    onabort 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型abort

    oncomplete 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型complete

    onerror 属性是一个 事件处理程序 IDL 属性,其 事件处理程序事件类型error

    注意: 要确定 事务 是否已成功完成,请监听 事务complete 事件,而不是特定 请求success 事件,因为在 success 事件触发后,事务 仍可能失败。

    5. 算法

    5.1. 打开数据库连接

    打开数据库连接(使用已请求打开 数据库storageKey、数据库 name、数据库 versionrequest),请执行以下步骤

    1. queuestorageKeyname连接队列

    2. request 添加到 queue 中。

    3. 等待直到 queue 中的所有先前请求均已处理完毕。

    4. dbstorageKey名为 name数据库,否则为 null。

    5. 如果 version 未定义,则在 db 为 null 时设 version 为 1,否则设为 db版本

    6. 如果 db 为 null,设 db 为一个新的 数据库,其 名称name版本 为 0,且没有 对象仓库。如果因任何原因失败,则返回适当的错误(例如 QuotaExceededError 或 "UnknownError" DOMException)。

    7. 如果 db版本 大于 version,则返回一个新 创建的 "VersionError" DOMException 并终止这些步骤。

    8. connection 为与 db 的新 连接

    9. 设置 connection版本version

    10. 如果 db版本 小于 version,则

      1. openConnections 为与 db 关联的所有 连接集合(不包括 connection)。

      2. 对于 openConnections 中的每个 entry(其 待关闭标志 未设置为 true),排队一个数据库任务,以在 entry触发一个版本变更事件,事件名为 versionchange,并携带 db版本version

        注意: 触发此事件可能会导致 openConnections 中的一个或多个其他对象被关闭,在这种情况下,即使尚未完成操作,也不会在这些对象上触发 versionchange 事件。

      3. 等待所有事件触发。

      4. 如果 openConnections 中的任何 连接 仍未关闭,则 排队一个数据库任务,以在 request触发一个版本变更事件,事件名为 blocked,并携带 db版本version

      5. 等待直到 openConnections 中的所有 连接已关闭

      6. 使用 connectionversionrequest 运行 升级数据库

      7. 如果 connection关闭,则返回一个新 创建的 "AbortError" DOMException 并终止这些步骤。

      8. 如果设置了 request错误,则运行 关闭数据库连接 的步骤(使用 connection),返回一个新 创建的 "AbortError" DOMException 并终止这些步骤。

    11. 返回 connection

    5.2. 关闭数据库连接

    关闭数据库连接(使用 connection 对象和一个可选的 forced flag),请执行以下步骤

    1. 设置 connection待关闭标志 为 true。

    2. 如果 forced flag 为 true,则对于每个使用 connection 创建的 transaction,运行 终止事务(使用 transaction 和新 创建的 "AbortError" DOMException)。

    3. 等待所有使用 connection 创建的 事务完成。一旦完成,connection已关闭

    4. 如果 forced flag 为 true,则在 connection触发一个事件,事件名为 close

      注意: close 事件仅在连接异常关闭时触发(例如,如果 存储键 的存储被清除,或者出现损坏或 I/O 错误)。如果明确调用了 close(),则该事件不会触发。

    注意: 一旦 连接待关闭标志 被设置为 true,就不能再使用该 连接 创建 新事务。所有 创建 事务的方法都会首先检查 连接待关闭标志,如果为 true,则抛出异常。

    注意: 一旦 连接 关闭,这可以取消 升级数据库删除数据库 的步骤的阻塞,这两个步骤 等待 对给定 数据库连接 在继续之前全部关闭。

    5.3. 删除数据库

    删除数据库(使用请求删除 数据库storageKey、数据库 namerequest),请执行以下步骤

    1. queuestorageKeyname连接队列

    2. request 添加到 queue 中。

    3. 等待直到 queue 中的所有先前请求均已处理完毕。

    4. dbstorageKey名为 name数据库(如果存在)。否则,返回 0。

    5. openConnections 为与 db 关联的所有 连接集合

    6. 对于 openConnections 中的每个 entry(其 待关闭标志 未设置为 true),排队一个数据库任务,以在 entry触发一个版本变更事件,事件名为 versionchange,并携带 db版本 和 null。

      注意: 触发此事件可能会导致 openConnections 中的一个或多个其他对象被关闭,在这种情况下,即使尚未完成操作,也不会在这些对象上触发 versionchange 事件。

    7. 等待所有事件触发。

    8. 如果 openConnections 中的任何 连接 仍未关闭,则 排队一个数据库任务,以在 request触发一个版本变更事件,事件名为 blocked,并携带 db版本 和 null。

    9. 等待直到 openConnections 中的所有 连接已关闭

    10. versiondb版本

    11. 删除 db。如果因任何原因失败,则返回适当的错误(例如 QuotaExceededError 或 "UnknownError" DOMException)。

    12. 返回 version

    5.4. 提交事务

    提交事务(使用待提交的 transaction),请执行以下步骤

    1. 设置 transaction状态正在提交

    2. 并行中 运行以下步骤:

      1. 等待直到 transaction请求列表 中的每个项目均 已处理

      2. 如果 transaction状态 不再是 正在提交,则终止这些步骤。

      3. 尝试将 transaction 所做的任何未决更改写入 数据库,同时考虑 transaction持久性提示

      4. 如果写入数据库的过程中发生错误,则运行 终止事务(使用 transaction 和适当的错误类型,例如 QuotaExceededError 或 "UnknownError" DOMException),并终止这些步骤。

      5. 排队一个数据库任务以运行以下步骤

        1. 如果 transaction升级事务,则将 transaction连接 所关联的 数据库升级事务 设置为 null。

        2. 设置 transaction状态已完成

        3. 触发一个事件,事件名为 complete,作用于 transaction

          注意: 即使从该事件的一个事件处理程序中抛出异常,事务也已提交,因为写入数据库的更改是在事件发生之前进行的。只有在事务成功写入后,才会触发 complete 事件。

        4. 如果 transaction升级事务,则设 request 为与 transaction 关联的 请求,并将 request事务 设置为 null。

    5.5. 终止事务

    终止事务(使用待终止的 transactionerror),请执行以下步骤

    1. 如果 transaction状态已完成,则终止这些步骤。

    2. 事务数据库 所做的所有更改均被撤销。对于 升级事务,这包括对 对象仓库索引 集合的更改,以及对 版本 的更改。在事务期间创建的任何 对象仓库索引 现在在其他算法看来均被视为已删除。

    3. 如果 transaction升级事务,请运行 终止升级事务 的步骤(使用 transaction)。

      注意: 这将撤销与 transaction 关联的所有 连接对象仓库句柄索引句柄 实例的更改。

    4. 设置 transaction状态已完成

    5. 设置 transaction错误error

    6. 对于 transaction请求列表 中的每个 request,终止 异步执行请求 的步骤,设置 request处理标志 为 true,并 排队一个数据库任务以运行以下步骤

      1. 设置 request完成标志 为 true。

      2. 设置 request结果 为 undefined。

      3. 设置 request错误 为一个新 创建的 "AbortError" DOMException

      4. 触发一个事件,事件名为 error,作用于 request,其 bubblescancelable 属性初始化为 true。

      注意: 这并不总是导致触发任何 error 事件。例如,如果事务由于在 提交 事务期间出错而被终止,或者如果它是最后一个失败的剩余请求。

    7. 排队一个数据库任务以运行以下步骤

      1. 如果 transaction升级事务,则将 transaction连接 所关联的 数据库升级事务 设置为 null。

      2. 触发一个事件,事件名为 abort,作用于 transaction,其 bubbles 属性初始化为 true。

      3. 如果 transaction升级事务,则

        1. request 为与 transaction 关联的 打开请求

        2. 设置 request事务 为 null。

        3. 设置 request结果 为 undefined。

        4. 设置 request处理标志 为 false。

        5. 设置 request完成标志 为 false。

    5.6. 异步执行 请求

    异步执行请求(使用 source 对象、要对数据库执行的 operation 和一个可选的 request),请执行以下步骤

    如果创建 request 所属的 事务终止(使用 终止事务 的步骤),则可以随时终止这些步骤。

    1. transaction 为与 source 关联的 事务

    2. 断言transaction状态活跃

    3. 如果未提供 request,设 request 为一个新的 请求,并将 source 作为其

    4. request 添加到 transaction请求列表 的末尾。

    5. 并行 中运行这些步骤

      1. 等待直到 request 成为 transaction请求列表 中未 处理 的第一项。

      2. result 为执行 operation 的结果。

      3. 如果 result 是一个错误且 transaction状态正在提交,则运行 终止事务(使用 transactionresult),并终止这些步骤。

      4. 如果 result 是一个错误,则撤销 operation 所做的所有更改。

        注意: 这仅撤销由此请求所做的更改,而不是事务所做的任何其他更改。

      5. 设置 request处理标志 为 true。

      6. 排队一个数据库任务以运行以下步骤

        1. transaction请求列表 中移除 request

        2. 设置 request完成标志 为 true。

        3. 如果 result 是错误,则

          1. 设置 request结果 为 undefined。

          2. 设置 request错误result

          3. 触发一个错误事件,作用于 request

        4. 否则

          1. 设置 request结果result

          2. 设置 request错误 为 undefined。

          3. 触发一个成功事件,作用于 request

    6. 返回 request

    5.7. 升级数据库

    升级数据库(使用 connection、新 versionrequest),请执行以下步骤

    1. dbconnection数据库

    2. transaction 为一个新的 升级事务,并将 connection 用作其 连接

    3. 设置 transaction范围connection对象仓库集合

    4. 设置 db升级事务transaction

    5. 设置 transaction状态不活跃

    6. 启动 transaction

      注意: 请注意,在此 事务 完成之前,无法打开到同一 数据库 的其他 连接

    7. old versiondb版本

    8. 设置 db版本version。此更改被视为 事务 的一部分,因此如果事务被 终止,此更改将被撤销。

    9. 设置 request处理标志 为 true。

    10. 排队一个数据库任务以运行以下步骤

      1. 设置 request结果connection

      2. 设置 request事务transaction

      3. request完成标记(done flag) 设置为 true。

      4. transaction状态 设置为 活跃(active)

      5. didThrow 为在 request 上以 old versionversion 触发名为 upgradeneeded版本变更事件 的结果。

      6. 如果 transaction状态活跃,则

        1. transaction状态 设置为 不活跃(inactive)

        2. 如果 didThrow 为 true,使用 transaction 和一个新 创建的 "AbortError" DOMException 运行 中止事务(abort a transaction)

    11. 等待 transaction 完成

      注意:事务生命周期 中调用的某些算法(例如 提交事务中止事务 的步骤)包含了针对 升级事务 的特定步骤。

    5.8. 中止升级事务

    要使用 transaction 中止升级事务,请运行以下步骤

    注意: 这些步骤由 中止事务 的步骤按需运行,它们会撤销对 数据库(包括关联的 对象存储空间索引 的集合)以及对 版本 的更改。

    1. connectiontransaction连接

    2. databaseconnection数据库

    3. 如果 database 之前存在,将 connection版本 设置为 database版本;如果 database 是新创建的,则设置为 0(零)。

      注意: 这会撤销 IDBDatabase 对象返回的 version 的值。

    4. 如果 database 之前存在,将 connection对象存储空间集合 设置为 database 中的 对象存储空间 集合;如果 database 是新创建的,则设置为集合为空。

      注意: 这会撤销 IDBDatabase 对象返回的 objectStoreNames 的值。

    5. 对于与 transaction 关联的每个 对象存储空间句柄 handle,包括在 transaction 期间创建或删除的 对象存储空间

      1. 如果 handle对象存储空间transaction 期间不是新创建的,将 handle名称 设置为其 对象存储空间名称

      2. handle索引集合 设置为引用其 对象存储空间索引 集合。

      注意: 这会撤销相关的 IDBObjectStore 对象返回的 nameindexNames 的值。

      这是如何观察到的?尽管在 事务 中止后,脚本无法通过 IDBTransaction 实例上的 objectStore() 方法访问 对象存储空间,但它仍然可以持有指向 IDBObjectStore 实例的引用,从中可以查询 nameindexNames 属性。
    6. 对于与 transaction 关联的每个 索引句柄 handle,包括在 transaction 期间创建或删除的 索引

      1. 如果 handle索引transaction 期间不是新创建的,将 handle名称 设置为其 索引名称

      注意: 这会撤销相关的 IDBIndex 对象返回的 name 值。

      这是如何观察到的?尽管在 事务 中止后,脚本无法通过 IDBObjectStore 实例上的 index() 方法访问 索引,但它仍然可以持有指向 IDBIndex 实例的引用,从中可以查询 name 属性。

    注意: IDBDatabase 实例的 name 属性不会被修改,即使被中止的 升级事务 是在创建新 数据库

    5.9. 触发成功事件

    要对 request 触发成功事件,请运行以下步骤

    1. event 为使用 Event 创建事件 的结果。

    2. eventtype 属性设置为 "success"。

    3. eventbubblescancelable 属性设置为 false。

    4. transactionrequest事务

    5. legacyOutputDidListenersThrowFlag 初始为 false。

    6. 如果 transaction状态不活跃,则将 transaction状态 设置为 活跃

    7. 使用 legacyOutputDidListenersThrowFlagrequest派发 event

    8. 如果 transaction状态活跃,则

      1. transaction状态 设置为 不活跃

      2. 如果 legacyOutputDidListenersThrowFlag 为 true,使用 transaction 和一个新 创建的 "AbortError" DOMException 运行 中止事务

      3. 如果 transaction请求列表 为空,则对 transaction 运行 提交事务

    5.10. 触发错误事件

    要对 request 触发错误事件,请运行以下步骤

    1. event 为使用 Event 创建事件 的结果。

    2. eventtype 属性设置为 "error"。

    3. eventbubblescancelable 属性设置为 true。

    4. transactionrequest事务

    5. legacyOutputDidListenersThrowFlag 初始为 false。

    6. 如果 transaction状态不活跃,则将 transaction状态 设置为 活跃

    7. 使用 legacyOutputDidListenersThrowFlagrequest派发 event

    8. 如果 transaction状态活跃,则

      1. transaction状态 设置为 不活跃

      2. 如果 legacyOutputDidListenersThrowFlag 为 true,则使用 transaction 和一个新 创建的 "AbortError" DOMException 运行 中止事务 并终止这些步骤。即使 event取消标记(canceled flag) 为 false,此步骤也会执行。

        注意: 这意味着如果触发了错误事件且任何事件处理程序抛出了异常,transactionerror 属性将被设置为 AbortError 而非 request错误,即使从未调用 preventDefault()

      3. 如果 event取消标记 为 false,则使用 transactionrequest错误 运行 中止事务,并终止这些步骤。

      4. 如果 transaction请求列表 为空,则对 transaction 运行 提交事务

    5.11. 克隆值

    克隆transaction 期间位于 targetRealm 中的 value,请运行以下步骤

    1. 断言transaction状态活跃

    2. transaction状态 设置为 不活跃

      注意: 使 事务 变为 不活跃,是为了防止由克隆操作触发的 getter 或其他副作用针对该事务发出额外请求。

    3. serialized? StructuredSerializeForStorage(value)。

    4. clone? StructuredDeserialize(serialized, targetRealm)。

    5. transaction状态 设置为 活跃

    6. 返回 clone

    5.12. 创建检索多个条目的请求

    创建检索多个条目的 请求,从 对象存储空间索引 中使用 targetRealmsourceHandlekindqueryOrOptions 以及可选的 count,请运行以下步骤

    1. source 为来自 sourceHandle索引对象存储空间。如果 sourceHandle 是一个 索引句柄,则 source该索引句柄关联的索引。否则,source该对象存储空间句柄关联的对象存储空间

    2. 如果 source 已被删除,抛出 一个 "InvalidStateError" DOMException

    3. 如果 source 是一个 索引 且其 对象存储空间 已被删除,抛出 一个 "InvalidStateError" DOMException

    4. transactionsourceHandle事务

    5. 如果 transaction状态 不为 活跃,则 抛出 一个 "TransactionInactiveError" DOMException

    6. range 为一个 键范围

    7. direction 为一个 游标方向

    8. 如果运行 是否为潜在有效的键范围 且使用 queryOrOptions 的结果为 true,则

      1. range 设置为 将值转换为键范围 且使用 queryOrOptions 的结果。重新抛出任何异常。

      2. direction 设置为 "next"。

    9. 否则:

      1. range 设置为 将值转换为键范围 且使用 queryOrOptions["query"] 的结果。重新抛出任何异常。

      2. count 设置为 queryOrOptions["count"]。

      3. direction 设置为 queryOrOptions["direction"]。

    10. operation 为要运行的算法。

    11. 如果 source 是一个 索引,将 operation 设置为 从索引中检索多个条目 且使用 targetRealmsourcerangekinddirection 以及(如果给定)count

    12. 否则,将 operation 设置为 从对象存储空间中检索多个条目 且使用 targetRealmsourcerangekinddirection 以及(如果给定)count

    13. 返回运行 异步执行请求 且使用 sourceHandleoperation 的结果(一个 IDBRequest)。

    注意: range 可以是一个 键范围(一个 IDBKeyRange),用于标识要检索的 记录 条目。如果为 null 或未给定,则使用 无界键范围。如果指定了 count 且范围内记录数量超过 count,则仅检索前 count 个记录。

    6. 数据库操作

    本节描述对 数据库对象存储空间索引 数据执行的各种操作。这些操作由 异步执行请求 的步骤运行。

    注意: 下面操作步骤中对 StructuredDeserialize() 的调用可以断言不会抛出异常(如 ! 前缀所示),因为它们仅对之前的 StructuredSerializeForStorage() 输出进行操作。

    6.1. 对象存储空间存储操作

    要使用 storevalue、可选的 key无覆盖标记(no-overwrite flag) 将记录存储到对象存储空间,请运行以下步骤

    1. 如果 store 使用 键生成器,则

      1. 如果 key 为 undefined,则

        1. key 为对 store 生成键 的结果。

        2. 如果 key 为失败,则此操作失败,产生 "ConstraintError" DOMException。中止此算法,不再采取进一步步骤。

        3. 如果 store 还使用 行内键(in-line keys),则使用 valuekeystore键路径 运行 使用键路径将键注入值

      2. 否则,使用 keystore 运行 可能更新键生成器

    2. 如果这些步骤接收到了 无覆盖标记 且为 true,并且 store 中已存在键 等于 key记录,则此操作失败,产生 "ConstraintError" DOMException。中止此算法,不再采取进一步步骤。

    3. 如果 store 中已存在键 等于 key记录,则使用 从对象存储空间中删除记录 将该 记录store 中移除。

    4. store 中存储一条记录,包含 key 作为其键,! StructuredSerializeForStorage(value) 作为其值。该记录被存储在对象存储空间的 记录列表 中,使得列表按记录的键以 升序 排序。

    5. 对于每个 引用 storeindex

      1. index key 为使用 valueindex键路径indexmultiEntry 标记 从值中提取键 的结果。

      2. 如果 index key 是异常、无效或失败,则不对 index 采取进一步操作,并继续为下一个索引运行这些步骤。

        注意: 此步骤中抛出的异常不会被重新抛出。

      3. 如果 indexmultiEntry 标记 为 false,或者如果 index key 不是 数组键,并且如果 index 已包含一个 记录,其 等于 index key,且 index唯一标记 为 true,则此操作失败,产生 "ConstraintError" DOMException。中止此算法,不再采取进一步步骤。

      4. 如果 indexmultiEntry 标记 为 true 且 index key 是一个 数组键,如果 index 已包含一个 记录,其 等于 index key 的任何 子键(subkeys),且 index唯一标记 为 true,则此操作失败,产生 "ConstraintError" DOMException。中止此算法,不再采取进一步步骤。

      5. 如果 indexmultiEntry 标记 为 false,或者如果 index key 不是一个 数组键,则在 index 中存储一条记录,包含 index key 作为其键,key 作为其值。该记录被存储在 index记录列表 中,使得列表首先按记录的键,其次按记录的值,以 升序 排序。

      6. 如果 indexmultiEntry 标记 为 true 且 index key 是一个 数组键,则对于 index key子键 中的每个 subkey,在 index 中存储一条记录,包含 subkey 作为其键,key 作为其值。该记录被存储在 index记录列表 中,使得列表首先按记录的键,其次按记录的值,以 升序 排序。

        注意: 没有 子键 是合法的。在这种情况下,不会向索引中添加任何记录。

        注意: 即使 子键 中的任何成员本身是一个 数组键,该成员也会直接用作索引记录的键。嵌套的 数组键 不会被扁平化或“解包”以产生多行;只有最外层的 数组键 会被使用。

    6. 返回 key

    6.2. 对象存储空间检索操作

    要使用 targetRealmstorerange 从对象存储空间中检索值,请运行以下步骤。它们返回 undefined、一个 ECMAScript 值或一个错误(一个 DOMException

    1. recordstore记录列表 中第一个其 range 之内的 记录(如有)。

    2. 如果未找到 record,则返回 undefined。

    3. serializedrecord。如果从底层存储读取值时发生错误,则返回一个新 创建的 "NotReadableError" DOMException

    4. 返回 ! StructuredDeserialize(serialized, targetRealm)。

    要使用 storerange 从对象存储空间中检索键,请运行以下步骤

    1. recordstore记录列表 中第一个其 range 之内的 记录(如有)。

    2. 如果未找到 record,则返回 undefined。

    3. 返回 将键转换为值 且使用 record 的键的结果。

    要使用 targetRealmstorerangekinddirection 以及可选的 count 从对象存储空间中检索多个条目,请运行以下步骤

    1. 如果 count 未给定或为 0(零),则令 count 为无穷大。

    2. records 为一个空的 记录列表

    3. 如果 direction 为 "next" 或 "nextunique",将 records 设置为 store记录列表 中前 count 个其 range 之内的记录。

    4. 如果 direction 为 "prev" 或 "prevunique",将 records 设置为 store记录列表 中最后 count 个其 range 之内的记录。

    5. list 为一个空 列表

    6. 对于 records 中的每个 record,根据 kind 进行切换

      "key"(关键)
      1. key将键转换为值 且使用 record 的键的结果。

      2. 追加 keylist

      "value"
      1. serializedrecord

      2. value! StructuredDeserialize(serialized, targetRealm)。

      3. 追加 valuelist

      "record"
      1. keyrecord 的键。

      2. serializedrecord

      3. value! StructuredDeserialize(serialized, targetRealm)。

      4. recordSnapshot 为一个新的 记录快照,其 设置为 key 设置为 value主键 设置为 key

      5. 追加 recordSnapshotlist

    7. 返回 list

    6.3. 索引检索操作

    要使用 targetRealmindexrange 从索引中检索引用的值,请运行以下步骤

    1. recordindex记录列表 中第一个其 range 之内的 记录(如有)。

    2. 如果未找到 record,则返回 undefined。

    3. serializedrecord引用值

    4. 返回 ! StructuredDeserialize(serialized, targetRealm)。

    要使用 indexrange 从索引中检索值,请运行以下步骤

    1. recordindex记录列表 中第一个其 range 之内的 记录(如有)。

    2. 如果未找到 record,则返回 undefined。

    3. 返回 将键转换为值 且使用 record 的结果。

    要使用 targetRealmindexrangekinddirection 以及可选的 count 从索引中检索多个条目,请运行以下步骤

    1. 如果 count 未给定或为 0(零),则令 count 为无穷大。

    2. records 为一个空的 记录列表

    3. 根据 direction 进行切换

      "next"
      1. records 设置为 index记录列表 中前 count 个其 range 之内的记录。

      "nextunique"
      1. rangeRecords 为一个包含 index记录列表 中其 range 之内的所有记录的列表。

      2. rangeRecordsLengthrangeRecords大小

      3. i 为 0。

      4. i 小于 rangeRecordsLength 时,则

        1. i 增加 1。

        2. 如果 record大小 等于 count,则 中断(break)

        3. 如果使用来自 |rangeRecords[i]| 和 |rangeRecords[i-1]| 的键 比较两个键 的结果相同,则 继续(continue)

        4. 否则 追加 |rangeRecords[i]| 到 records

      "prev"
      1. records 设置为 index记录列表 中最后 count 个其 range 之内的记录。

      "prevunique"
      1. rangeRecords 为一个包含 index记录列表 中其 range 之内的所有记录的列表。

      2. rangeRecordsLengthrangeRecords大小

      3. i 为 0。

      4. i 小于 rangeRecordsLength 时,则

        1. i 增加 1。

        2. 如果 record大小 等于 count,则 中断

        3. 如果使用来自 |rangeRecords[i]| 和 |rangeRecords[i-1]| 的键 比较两个键 的结果相同,则 继续

        4. 否则 插入到开头(prepend) |rangeRecords[i]| 到 records

    4. list 为一个空 列表

    5. 对于 records 中的每个 record,根据 kind 进行切换

      "key"(关键)
      1. key将键转换为值 且使用 record 的值的结果。

      2. 追加 keylist

      "value"
      1. serializedrecord引用值

      2. value! StructuredDeserialize(serialized, targetRealm)。

      3. 追加 valuelist

      "record"
      1. index keyrecord 的键。

      2. keyrecord 的值。

      3. serializedrecord引用值

      4. value! StructuredDeserialize(serialized, targetRealm)。

      5. recordSnapshot 为一个新的 记录快照,其 设置为 index key 设置为 value主键 设置为 key

      6. 追加 recordSnapshotlist

    6. 返回 list

    一致性

    文档约定

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

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

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

    这是一个说明性示例。

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

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

    一致性算法

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

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

    索引

    本规范定义的术语

  • 请求列表,位于 § 2.7
  • 结果
  • 从对象存储中检索键,位于 § 6.2
  • 从索引中检索引用值,位于 § 6.3
  • 从索引中检索值,位于 § 6.3
  • 从对象存储中检索值,位于 § 6.2
  • 从索引中检索多个项目,位于 § 6.3
  • 从对象存储中检索多个项目,位于 § 6.2
  • 作用域,位于 § 2.7
  • source
  • 源句柄,位于 § 2.10
  • 开始,位于 § 2.7.1
  • 已开始,位于 § 2.7.1
  • 状态,位于 § 2.7.1
  • 将记录存储到对象存储中,位于 § 6.1
  • "strict",位于 § 4.4
  • 子键,位于 § 2.4
  • 成功,位于 § 2.8
  • 交易
  • transaction(storeNames),位于 § 4.4
  • transaction(storeNames, mode),位于 § 4.4
  • transaction(storeNames, mode, options),位于 § 4.4
  • 类型,位于 § 2.4
  • 无界键范围,位于 § 2.9
  • unique
  • 唯一性标志,位于 § 2.6
  • update(value),位于 § 4.9
  • 升级数据库,位于 § 5.7
  • upgradeneeded,位于 § 2.8.1
  • 升级事务
  • upper,位于 § 4.7
  • 上界,位于 § 2.9
  • upperBound(upper),位于 § 4.7
  • upperBound(upper, open),位于 § 4.7
  • upperOpen,位于 § 4.7
  • 上开标志,位于 § 2.9
  • 有效的键路径,位于 § 2.5
  • value
  • ,位于 § 2.6
  • version
  • "versionchange",位于 § 4.10
  • versionchange,位于 § 2.1.1
  • 通过引用定义的术语

    引用

    规范性引用

    [DOM]
    Anne van Kesteren. DOM 标准. Living Standard. URL: https://dom.spec.whatwg.org/
    [ECMA-262]
    ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
    [FileAPI]
    Marijn Kruisselbrink. 文件 API. 2024 年 12 月 4 日. WD. URL: https://w3org.cn/TR/FileAPI/
    [HTML]
    Anne van Kesteren; et al. HTML 标准. Living Standard. URL: https://html.whatwg.cn/multipage/
    [INFRA]
    Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
    [RFC2119]
    S. Bradner. RFC 中用于指示要求级别的关键词. 1997年3月. Best Current Practice. 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 标准. Living Standard. URL: https://webidl.spec.whatwg.org/

    参考资料

    [Charmod-Norm]
    Addison Phillips 等人. 万维网字符模型:字符串匹配. 2021 年 8 月 11 日. NOTE. URL: https://w3org.cn/TR/charmod-norm/
    [COOKIES]
    A. Barth. HTTP 状态管理机制. 2011 年 4 月. Proposed Standard. URL: https://httpwg.org/specs/rfc6265.html
    [WEBSTORAGE]
    Ian Hickson. Web 存储(第二版). 2021 年 1 月 28 日. 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)]
    interface IDBVersionChangeEvent : Event {
      constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
      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 mixin 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);
    
      Promise<sequence<IDBDatabaseInfo>> databases();
    
      short cmp(any first, any second);
    };
    
    dictionary IDBDatabaseInfo {
      DOMString name;
      unsigned long long version;
    };
    
    [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",
                                             optional IDBTransactionOptions options = {});
      undefined close();
    
      [NewObject] IDBObjectStore createObjectStore(
        DOMString name,
        optional IDBObjectStoreParameters options = {});
      undefined deleteObjectStore(DOMString name);
    
      // Event handlers:
      attribute EventHandler onabort;
      attribute EventHandler onclose;
      attribute EventHandler onerror;
      attribute EventHandler onversionchange;
    };
    
    enum IDBTransactionDurability { "default", "strict", "relaxed" };
    
    dictionary IDBTransactionOptions {
      IDBTransactionDurability durability = "default";
    };
    
    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 queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                        optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
      [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 = {});
      undefined deleteIndex(DOMString name);
    };
    
    dictionary IDBIndexParameters {
      boolean unique = false;
      boolean multiEntry = false;
    };
    
    dictionary IDBGetAllOptions {
      any query = null;
      [EnforceRange] unsigned long count;
      IDBCursorDirection direction = "next";
    };
    
    [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 queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                        optional [EnforceRange] unsigned long count);
      [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
      [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 IDBRecord {
      readonly attribute any key;
      readonly attribute any primaryKey;
      readonly attribute any value;
    };
    
    [Exposed=(Window,Worker)]
    interface IDBCursor {
      readonly attribute (IDBObjectStore or IDBIndex) source;
      readonly attribute IDBCursorDirection direction;
      readonly attribute any key;
      readonly attribute any primaryKey;
      [SameObject] readonly attribute IDBRequest request;
    
      undefined advance([EnforceRange] unsigned long count);
      undefined continue(optional any key);
      undefined 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;
      readonly attribute IDBTransactionDurability durability;
      [SameObject] readonly attribute IDBDatabase db;
      readonly attribute DOMException? error;
    
      IDBObjectStore objectStore(DOMString name);
      undefined commit();
      undefined abort();
    
      // Event handlers:
      attribute EventHandler onabort;
      attribute EventHandler oncomplete;
      attribute EventHandler onerror;
    };
    
    enum IDBTransactionMode {
      "readonly",
      "readwrite",
      "versionchange"
    };
    
    
    MDN

    IDBCursor/advance

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/continue

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/continuePrimaryKey

    在所有当前引擎中。

    Firefox10+Safari10.1+Chrome58+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android51+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/delete

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/direction

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/key

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/primaryKey

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/request

    在所有当前引擎中。

    Firefox77+Safari15+Chrome76+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/source

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor/update

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursor

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera44+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile43+
    MDN

    IDBCursorWithValue/value

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBCursorWithValue

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBDatabase/close

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/close_event

    在所有当前引擎中。

    Firefox50+Safari10.1+Chrome30+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/close_event

    在所有当前引擎中。

    Firefox50+Safari10.1+Chrome30+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/createObjectStore

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/deleteObjectStore

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/name

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/objectStoreNames

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/transaction

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/version

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/versionchange_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase/versionchange_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBDatabase

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBFactory/cmp

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBFactory/databases

    FirefoxNoneSafari14+Chrome72+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBFactory/deleteDatabase

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBFactory/open

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBFactory

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBIndex/count

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/get

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/getAll

    在所有当前引擎中。

    Firefox44+Safari10.1+Chrome48+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/getAllKeys

    在所有当前引擎中。

    Firefox44+Safari10.1+Chrome48+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/getKey

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/keyPath

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/multiEntry

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/name

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/objectStore

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/openCursor

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/openKeyCursor

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex/unique

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBIndex

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBKeyRange/bound_static

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/includes

    在所有当前引擎中。

    Firefox47+Safari10.1+Chrome52+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/lower

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/lowerBound_static

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/lowerOpen

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/only_static

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/upper

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/upperBound_static

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange/upperOpen

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBKeyRange

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBObjectStore/add

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/autoIncrement

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)?IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/clear

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/count

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/createIndex

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/delete

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/deleteIndex

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/get

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/getAll

    在所有当前引擎中。

    Firefox44+Safari10.1+Chrome48+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/getAllKeys

    在所有当前引擎中。

    Firefox44+Safari10.1+Chrome48+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/getKey

    在所有当前引擎中。

    Firefox51+Safari10.1+Chrome48+
    Opera45+Edge79+
    Edge (旧版)?IE
    Firefox for Android58+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile43+
    MDN

    IDBObjectStore/index

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/indexNames

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/keyPath

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/name

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/openCursor

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/openKeyCursor

    在所有当前引擎中。

    Firefox44+Safari10.1+Chrome23+
    Opera?Edge79+
    Edge (Legacy)?IE10+
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/put

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore/transaction

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBObjectStore

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBOpenDBRequest/blocked_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBOpenDBRequest/upgradeneeded_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBOpenDBRequest

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBRequest/error

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/error_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

    IDBTransaction/error_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/readyState

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/result

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/source

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/success_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest/transaction

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBRequest

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android25+Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBTransaction/abort

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/abort_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/commit

    在所有当前引擎中。

    Firefox74+Safari15+Chrome76+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/complete_event

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/db

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/durability

    FirefoxNoneSafari15+Chrome83+
    Opera70+Edge83+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/error

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/mode

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/objectStore

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction/objectStoreNames

    在所有当前引擎中。

    Firefox10+Safari10.1+Chrome48+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBTransaction

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera15+Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
    MDN

    IDBVersionChangeEvent/IDBVersionChangeEvent

    在所有当前引擎中。

    Firefox25+Safari10+Chrome41+
    Opera?Edge79+
    Edge (旧版)?IE
    Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBVersionChangeEvent/newVersion

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBVersionChangeEvent/oldVersion

    在所有当前引擎中。

    Firefox10+Safari8+Chrome23+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
    MDN

    IDBVersionChangeEvent

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile?
    MDN

    indexedDB

    在所有当前引擎中。

    Firefox16+Safari8+Chrome24+
    Opera?Edge79+
    Edge (Legacy)12+IE10+
    Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?