indexDB
IndexDB 是一个运行在浏览器上的非关系型数据库。理论上是没有存储上限的一般来说不会小于 250M)。它不仅可以存储字符串,还可以存储二进制数据。
特点:
键值对储存 所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
异步 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
同源限制 每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
支持二进制储存
储存空间大
idb 库
reference
- 安装
shell
pnpm add idb- 示例
ts
import { openDB, type DBSchema } from 'idb'
type Schema<T extends DBSchema> = {
[P in keyof T]: T[P]['indexes'] extends Recordable
? {
indexes: (keyof T[P]['indexes'])[]
}
: object
}
interface Config<T extends DBSchema> {
SCHEMA: Schema<T>
DB_NAME: string
DB_VERSION: number
}
// 1. 先定义数据库类型
interface MyDB extends DBSchema {
todo: {
key: string
value: number
}
dictionary: {
value: {
label: string
meaning: string
level: 'cet4' | 'cet6' | 'high_school'
}
key: number // 主索引
indexes: { label: string }
}
}
// 2. 定义完整信息
const DB_CONFIG: Config<MyDB> = {
SCHEMA: {
dictionary: {
indexes: ['level'],
},
todo: {},
},
DB_NAME: 'my-db',
DB_VERSION: 1,
}
export async function demo() {
const { DB_NAME, DB_VERSION, SCHEMA } = DB_CONFIG
// 3. 赋值即可
const db = await openDB<MyDB>(DB_NAME, DB_VERSION, {
upgrade(db) {
/*
* 根据 SCHEMA 创建对应的表
* indexes 存在的话,就创建对应的索引;
* value 为对象类型,默认使用 id 作为主键(自增)
*
*/
const createdStoreKeys = Object.values(db.objectStoreNames)
const storeKeys = Object.keys(SCHEMA) as typeof createdStoreKeys
const unCreate = storeKeys.filter((store) => !createdStoreKeys.includes(store))
if (unCreate.length) {
unCreate.forEach((store) => {
const indexes = (Reflect.get(SCHEMA, store) as Recordable)['indexes'] as
| null
| string[]
const s = db.createObjectStore(
store,
indexes
? {
keyPath: 'id',
autoIncrement: true,
}
: undefined
)
if (indexes) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
indexes.forEach((index) => s.createIndex(index, index))
}
})
}
},
})
// value 是对象,那么就可以不传递 key 属性
db.put('dictionary', {
label: 'hi',
meaning: '你好2',
level: 'cet4',
})
// value 是 number,需要传递对应的 key(唯一),相同的时候就是更新
db.put('todo', 1, 'someKey')
// 根据索引查询(从 dictionary 中查找索引 level = cet4)
db.getAllFromIndex('dictionary', 'level', 'cet4')
// 根据主索引查询(id=1)
db.get('dictionary', 1)
// 根据主索引查询(附加 id >= 2 条件)
db.getAll('dictionary', IDBKeyRange.lowerBound(2))
// 删除
db.delete('dictionary', IDBKeyRange.lowerBound(5))
}