前端本地化存储算是一个老生常谈的话题了,我们对于 cookies、Web Storage(sessionStorage、localStorage)
的使用已经非常熟悉,在面试与实际操作之中也会经常遇到相关的问题,但这些本地化存储的方式还存在一些缺陷,比较明显的缺点如下:
- 存储量小:即使是web storage的存储量最大也只有 5M;
- 存取不方便:存入的内容会经过序列化,当存入非字符串的时候,取值的时候需要通过反序列化。
当我们的存储量比较大的时候,我们一定会想到我们的 indexedDB
,让我们在浏览器中也可以使用数据库这种形式来玩转本地化存储,然而 indexedDB
的使用是比较繁琐而复杂的,有一定的学习成本,但第三方库 localForage
的出现,让我们轻松无负担的在浏览器中使用 indexedDB
。
截止今天,localForage
在 github
的 star
已经23.4k
了,可以说 localForage
和 indexedDB
算是相互成就了。
通俗地说,IndexedDB
就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB
允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage
所不具备的。就数据库类型而言,IndexedDB
不属于关系型数据库(不支持 SQL
查询语句),更接近 NoSQL
数据库。
IndexedDB
具有以下特点。
(1)键值对储存。 IndexedDB
内部采用对象仓库(object store
)存放数据。所有类型的数据都可以直接存入,包括 JavaScript
对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
(2)异步。 IndexedDB
操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage
形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
(3)支持事务。 IndexedDB
支持事务(transaction
),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
(4)同源限制。 IndexedDB
受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
(5)储存空间大。 IndexedDB
的储存空间比 LocalStorage
大得多,一般来说不少于 250MB
,甚至没有上限。
(6)支持二进制储存。 IndexedDB
不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer
对象和 Blob
对象)。
localForage
是基于 indexedDB
封装的库,通过它我们可以简化 IndexedDB
的使用。
但是你也不必太过担心,因为 localforage
有一个降级策略,若浏览器不支持 IndexedDB
则使用 WebSQL
,如果不支持 WebSQL
则使用 localStorage
。在所有主流浏览器中都可用:Chrome
,Firefox
,IE
和 Safari
(包括 Safari Mobile
)。
localForage
// 下载
npm i localforage
or
pnpm add localforage
// 引入
import localforage from 'localforage'
const myIndexedDB = localforage.createInstance({
name: 'myIndexedDB',
})
myIndexedDB.setItem(key, value)
由于indexedDB的存取都是异步的,建议使用 promise.then() 或 async/await 去读值
myIndexedDB.getItem('somekey').then(function (value) {
// we got our value
}).catch(function (err) {
// we got an error
});
or
try {
const value = await myIndexedDB.getItem('somekey');
// This code runs once the value has been loaded
// from the offline store.
console.log(value);
} catch (err) {
// This code runs if there were any errors.
console.log(err);
}
myIndexedDB.removeItem('somekey')
myIndexedDB.clear()
如果你想使用多个数据库,建议通过 pinia
统一管理所有的数据库,这样数据的流向会更明晰,数据库相关的操作都写在 store
中,让你的数据库更规范化。
// store/indexedDB.ts
import { defineStore } from 'pinia'
import localforage from 'localforage'
export const useIndexedDBStore = defineStore('indexedDB', {
state: () => ({
filesDB: localforage.createInstance({
name: 'filesDB',
}),
usersDB: localforage.createInstance({
name: 'usersDB',
}),
responseDB: localforage.createInstance({
name: 'responseDB',
}),
}),
actions: {
async setfilesDB(key: string, value: any) {
this.filesDB.setItem(key, value)
},
}
})
我们使用的时候,就直接调用 store
中的方法
import { useIndexedDBStore } from '@/store/indexedDB'
const indexedDBStore = useIndexedDBStore()
const file1 = {a: 'hello'}
indexedDBStore.setfilesDB('file1', file1)