IndexedDB
使用对象仓库、索引、游标和事务持久保存结构化记录。
IndexedDB 提供结构化数据库,支持对象仓库、索引、游标和事务,适合保存需要查询和一致性保障的数据。
先创建并关联资源;关联与共享规则见模块概览。
import { IndexedDB } from 'lexmount:storage';IndexedDB 为 IDBFactory,与 globalThis.indexedDB 是同一对象。以下 API 使用事件请求和事务,不能把 IDBRequest 当作 Promise 使用。IDB* 类型和 IDBKeyRange 可直接使用,无需额外导入。
键、查询与批量读取选项
| 类型 / 参数 | 说明 |
|---|---|
IDBValidKey | 有效数字、Date、字符串、二进制键或这些类型组成的复合键数组;NaN、无效 Date、null 和 undefined 不是有效键 |
query | IDBValidKey 或 IDBKeyRange;标为可选的方法省略时查询全部记录 |
direction | 'next'(默认)、'nextunique'、'prev'、'prevunique',控制顺序与重复索引键 |
count | 可选的 0~4294967295 整数,限制批量读取数量;省略或 0 表示不按数量限制 |
IDBGetAllOptions | { query?, count?, direction? },字段含义同上;可作为 getAll()、getAllKeys() 的首参,也供 getAllRecords() 使用 |
IDBRecord | { key, primaryKey, value };key 为查询对象的键,primaryKey 为对象仓库主键,value 为记录值 |
普通对象、数组、循环引用、undefined、BigInt、Date、RegExp、Map、Set、Error、ArrayBuffer / TypedArray、Blob / File 等可克隆值可以保存。函数和不支持的宿主对象会导致 DataCloneError。业务值不局限于 JSON。
IndexedDB.open(name, version?)
功能: 打开已有且已关联的数据库,必要时执行结构升级。
参数: name: string 必填,为资源名称;version?: number 为正整数,省略时打开当前版本。控制台新建的空库版本为 0,首次打开升级到版本 1,可在 upgradeneeded 中创建对象仓库和索引。
返回值: IDBOpenDBRequest,同步返回。success 时 result 是 IDBDatabase;不存在或未关联时通过请求 error 事件返回 NotFoundError,不会创建数据库。
IndexedDB.databases()
功能: 列出当前实例已关联的数据库。
参数: 无。
返回值: Promise<IDBDatabaseInfo[]>,各项包含数据库 name 和数字 version。
IndexedDB.cmp(first, second)
功能: 按 IndexedDB 键顺序比较两个键。
参数: first、second 必填,均为 IDBValidKey。
返回值: 同步返回 -1、0 或 1,分别表示小于、相等或大于;非法键抛出 DataError。
IndexedDB.deleteDatabase(name)
功能: 此运行时禁止通过代码删除数据库,资源需在控制台删除。
参数: name: string 为标准接口的数据库名参数。
返回值: 不会返回请求对象,始终同步抛出 NotAllowedError。
IDBDatabase
通过成功的打开请求获得 db。数据库、对象仓库和索引名称最多 1024 UTF-8 字节,不能包含 NUL 或无效 Unicode。
| 属性 | 类型 | 说明 |
|---|---|---|
name | string | 数据库名,只读 |
version | number | 当前版本,只读 |
objectStoreNames | DOMStringList | 对象仓库名称,只读列表 |
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
db.createObjectStore(name, options?) | 在升级事务中创建对象仓库 | 必填名称;options.keyPath?: string | string[] | null 默认 null;options.autoIncrement?: boolean 默认 false | IDBObjectStore,同步返回 |
db.deleteObjectStore(name) | 在升级事务中删除对象仓库及其记录、索引 | 必填 name: string | void |
db.transaction(storeNames, mode?, options?) | 开始事务 | 必填单个仓库名或名称数组;mode 为 readonly(默认)或 readwrite;options.durability 为 default(默认)、strict 或 relaxed | IDBTransaction |
db.close() | 关闭连接,已有事务完成后释放连接 | 无 | void |
创建和删除对象仓库应在 upgradeneeded 的升级事务中进行,应用日常读写使用 readonly 或 readwrite 事务。durability 接受标准值,但当前均等待后端提交。
数据库支持 onversionchange、onclose、onerror 和 onabort 事件属性。版本事件含 oldVersion: number、newVersion: number | null。同一运行时内支持版本协调;跨实例升级不会广播浏览器式版本事件,需由应用协调并重新打开旧连接。
IDBTransaction
| 属性 | 类型 | 说明 |
|---|---|---|
db | IDBDatabase | 所属连接 |
mode | IDBTransactionMode | readonly、readwrite 或升级用的 versionchange |
durability | IDBTransactionDurability | 事务的持久性选项 |
objectStoreNames | DOMStringList | 本事务可访问的仓库名 |
error | DOMException / null | 事务错误,无错误时为 null |
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
tx.objectStore(name) | 获取事务范围内的仓库 | 必填 name: string | IDBObjectStore |
tx.commit() | 显式开始提交,不再接受新请求 | 无 | void;完成仍需等待 complete |
tx.abort() | 中止并回滚本事务 | 无 | void |
oncomplete 表示后端提交成功,onabort 表示中止,onerror 可观察请求错误。单个请求 success 不代表已持久化。事务会自动提交,发起请求时必须处于活动状态;不要在事务中等待不相关的网络请求或定时器再继续读写。
IDBRequest 与 IDBOpenDBRequest
| 属性 | 类型 | 说明 |
|---|---|---|
result | 依操作而定 | 请求成功的结果;完成前读取会抛出 InvalidStateError |
error | DOMException / null | 请求错误;完成前读取会抛出 InvalidStateError |
source | IDBObjectStore / IDBIndex / IDBCursor / null | 请求来源 |
transaction | IDBTransaction / null | 所属事务;打开请求在升级阶段提供升级事务 |
readyState | 'pending' / 'done' | 请求状态 |
普通请求通过 onsuccess / onerror 接收结果。打开请求另有 onupgradeneeded 和 onblocked;升级事件提供 oldVersion 和 newVersion。
请求、事务和数据库支持事件属性以及 EventTarget 的 addEventListener(type, listener, options?)、removeEventListener(type, listener, options?) 和 dispatchEvent(event);前两者返回 void,最后一个返回 boolean。listener 为回调或事件监听对象,options 可控制 capture、once 等标准监听行为。处理请求错误时,可调用事件的 preventDefault() 阻止默认中止,再由应用决定事务处理。
IDBObjectStore
store.name: string 可在升级事务中修改;其余属性为只读:keyPath: string | string[] | null、autoIncrement: boolean、indexNames: DOMStringList、transaction: IDBTransaction。
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
store.add(value, key?) | 新增记录,重复主键报 ConstraintError | 必填可克隆 value;可选主键;使用内联 keyPath 时不另传 key | IDBRequest<IDBValidKey>,结果为主键 |
store.put(value, key?) | 新增或替换同主键记录 | 参数同 add | IDBRequest<IDBValidKey> |
store.get(query) | 读取首条匹配记录 | 必填键或键范围 | IDBRequest<any>,未找到时结果为 undefined |
store.getKey(query) | 读取首个匹配主键 | 必填键或键范围 | IDBRequest,结果为键或 undefined |
store.getAll(query?, count?) | 批量读取记录值 | 可选查询和数量,或首参传 IDBGetAllOptions | IDBRequest<any[]>,未找到时为 [] |
store.getAllKeys(query?, count?) | 批量读取主键 | 参数同 getAll | IDBRequest<IDBValidKey[]> |
store.getAllRecords(options?) | 批量读取键、主键和值 | 可选 IDBGetAllOptions | IDBRequest<IDBRecord[]> |
store.count(query?) | 统计匹配记录 | 可选键或键范围,省略时统计全部 | IDBRequest<number> |
store.delete(query) | 删除匹配记录 | 必填键或键范围 | IDBRequest<undefined> |
store.clear() | 删除仓库内全部记录 | 无 | IDBRequest<undefined> |
store.openCursor(query?, direction?) | 逐条遍历键与值 | 可选查询和方向 | IDBRequest,结果为 IDBCursorWithValue 或 null |
store.openKeyCursor(query?, direction?) | 仅遍历键 | 可选查询和方向 | IDBRequest,结果为 IDBCursor 或 null |
store.createIndex(name, keyPath, options?) | 创建索引,仅升级事务可用 | 必填名称、字符串或字符串数组 keyPath;unique?: boolean、multiEntry?: boolean 均默认 false | IDBIndex,同步返回 |
store.index(name) | 获取现有索引 | 必填 name: string | IDBIndex |
store.deleteIndex(name) | 删除索引,仅升级事务可用 | 必填 name: string | void |
写操作需要 readwrite 或升级事务。keyPath 从 value 中取键;autoIncrement 可生成键,具体组合仍受 IndexedDB 键规则约束。复合 keyPath 不能与 multiEntry 同时启用。
IDBIndex
index.name: string 可在升级事务中修改;只读属性包括 objectStore: IDBObjectStore、keyPath: string | string[]、unique: boolean、multiEntry: boolean。
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
index.get(query) | 按索引键读取首条记录值 | 必填键或键范围 | IDBRequest<any>,未找到时为 undefined |
index.getKey(query) | 按索引键读取首个主键 | 必填键或键范围 | IDBRequest,结果为主键或 undefined |
index.getAll(query?, count?) | 按索引批量读取值 | 可选查询和数量,或首参传 IDBGetAllOptions | IDBRequest<any[]> |
index.getAllKeys(query?, count?) | 按索引批量读取主键 | 参数同 getAll | IDBRequest<IDBValidKey[]> |
index.getAllRecords(options?) | 读取索引键、主键和值 | 可选 IDBGetAllOptions | IDBRequest<IDBRecord[]> |
index.count(query?) | 统计匹配的索引条目 | 可选查询,省略时统计全部 | IDBRequest<number> |
index.openCursor(query?, direction?) | 按索引顺序遍历记录 | 可选查询和方向 | IDBRequest,结果为 IDBCursorWithValue 或 null |
index.openKeyCursor(query?, direction?) | 按索引顺序遍历键 | 可选查询和方向 | IDBRequest,结果为 IDBCursor 或 null |
空的批量结果为 []。multiEntry 索引可能为同一记录提供多个条目,索引的 count 统计条目数;唯一索引遇到冲突会使相应写请求失败。
IDBCursor 与 IDBCursorWithValue
| 属性 | 类型 | 说明 |
|---|---|---|
source | IDBObjectStore / IDBIndex | 游标来源 |
direction | IDBCursorDirection | 遍历方向 |
key | IDBValidKey | 当前查询键,索引游标中为索引键 |
primaryKey | IDBValidKey | 当前记录主键 |
request | IDBRequest | 驱动游标的请求 |
value | any | 当前记录值,仅 IDBCursorWithValue 提供 |
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
cursor.advance(count) | 向当前方向前进多条 | 必填正整数 count | void |
cursor.continue(key?) | 前进到下一项或指定键 | 可选有效键,必须沿当前方向前进 | void |
cursor.continuePrimaryKey(key, primaryKey) | 前进到指定索引键与主键位置 | 两个有效键必填;仅 next / prev 的索引游标可用 | void |
cursor.update(value) | 替换当前记录 | 必填可克隆 value,需要可写事务和值游标 | IDBRequest<IDBValidKey> |
cursor.delete() | 删除当前记录 | 无,需要可写事务和值游标 | IDBRequest<undefined> |
advance / continue 不返回下一项;它们让原请求再次触发 success,通过 request.result 取得下一游标,遍历结束时为 null。一次前进完成前不能再次前进。
IDBKeyRange
用静态方法构建键范围。返回对象具有只读 lower、upper(有效键或未设边界时的 undefined)以及布尔属性 lowerOpen、upperOpen。
| 方法 | 功能 | 参数 | 返回值 |
|---|---|---|---|
IDBKeyRange.only(value) | 仅匹配一个键 | 必填有效键 value | IDBKeyRange |
IDBKeyRange.lowerBound(lower, open?) | 设置下界 | 必填有效键 lower;open 默认 false | IDBKeyRange |
IDBKeyRange.upperBound(upper, open?) | 设置上界 | 必填有效键 upper;open 默认 false | IDBKeyRange |
IDBKeyRange.bound(lower, upper, lowerOpen?, upperOpen?) | 设置双边范围 | 两个有效键必填;两个开放边界开关默认 false | IDBKeyRange |
range.includes(key) | 检查键是否在范围内 | 必填有效键 key | boolean |
Open 为 true 表示不包含该边界。无效键、颠倒范围或不可成立的边界组合会抛出 DataError。
DOMStringList(例如 objectStoreNames / indexNames)提供 length: number、数字下标、item(index): string | null 和 contains(name): boolean,并可迭代。item 的 index 为数字,contains 的 name 为字符串。
事务示例与限制
import { IndexedDB } from 'lexmount:storage';
const request = IndexedDB.open('application', 1);
request.onupgradeneeded = () => {
request.result.createObjectStore('notes', { keyPath: 'id' });
};
const db = await new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
try {
const tx = db.transaction('notes', 'readwrite');
const completed = new Promise((resolve, reject) => {
tx.oncomplete = resolve;
tx.onabort = () => reject(tx.error);
});
tx.objectStore('notes').put({ id: 'first', title: 'Hello' });
await completed;
} finally {
db.close();
}单条序列化记录、键、结构元数据及查询结果页上限为 64 MiB,不代表整个数据库的大小上限。数据库连接获取、锁等待、SQL 和事务空闲超时为 30 秒。长事务会阻塞写入;大文件适合放对象存储。
同一资源共享已提交数据,事务中止会回滚。跨实例升级需统一协调,旧连接可能失效并需要重开;连接在提交后断开时可能无法确认结果,重试写入应使用稳定主键。此数据库与网页自身的 window.indexedDB 独立。
请求与事务的错误处理见 IDBRequest,声明见 storage.d.ts。
