參考網站
localStorage 是前端本地儲存的一種,其容量一般在 5M-10M 左右,用來快取一些簡單的資料基本夠用,畢竟定位也不是大資料量的儲存。
在某些場景下 localStorage 的容量就會有點捉襟見肘,其實瀏覽器是有提供大資料量的本地儲存的如 IndexedDB 儲存資料大小一般在 250M 以上。
彌補了 localStorage 容量的缺陷,但是使用要比 localStorage 複雜一些 mdn IndexedDB
不過已經有大佬造了輪子封裝了一些呼叫過程使其使用相對簡單,下面我們一起來看一下~
localforage
localforage,擁有類似 localStorage API,它能儲存多種型別的資料如 Array、ArrayBuffer、Blob、Number、Object、String,而不僅僅是字串。
這意味著我們可以直接存 物件、陣列型別的資料避免了 JSON.stringify 轉換資料的一些問題。
儲存其他資料型別時需要轉換成上邊對應的型別,比如 vue3 中使用 reactive 定義的資料需要使用 toRaw 轉換成原始資料進行儲存, ref 則直接儲存 xxx.value 資料即可。
安裝
下載最新版本 或使用 npm、bower 進行安裝,引入下載的 localforage 即可使用。
1
| npm install localforage
|
1
| bower install localforage
|
使用
提供了與 localStorage 相同的api,不同的是它是非同步的呼叫返回一個 Promise 物件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| localforage.getItem('somekey')
.then(function(value) {
// 當離線倉庫中的值被載入時,此處程式碼執行
console.log(value);
})
.catch(function(err) {
// 當出錯時,此處程式碼執行
console.log(err);
});
// callback 版本
localforage.getItem('somekey', function(err, value) {
// 當離線倉庫中的值被載入時,此處程式碼執行
console.log(value);
});
|
提供的方法
getItem: 根據資料的 key 獲取資料 不存在則返回 null。setItem: 根據資料的 key 設定資料(儲存 undefined 時 getItem 獲取會返回 null)。removeItem: 根據 key 刪除資料。length: 獲取 key 的數量。key: 根據 key 的索引獲取其名。keys: 獲取資料倉庫中所有的 key。iterate: 迭代資料倉庫中的所有 value/key 鍵值對。
配置
完整配置可檢視文件
這裡說個我覺得很有用的:
1
| localforage.config({ name: 'My-localStorage' });
|
設定倉庫的名字,不同的名字代表不同的倉庫,當一個應用需要多個本地倉庫隔離資料的時候就很有用。
1
2
3
4
5
6
| const store = localforage.createInstance({ name: "nameHere" });
const otherStore = localforage.createInstance({ name: "otherName" });
// 設定某個資料倉庫 key 的值不會影響到另一個數據倉庫
store.setItem("key", "value");
otherStore.setItem("key", "value2");
|
同時也支援刪除倉庫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 呼叫時,若不傳參,將刪除當前例項的 “資料倉庫”。
localforage.dropInstance()
.then(function() {
console.log('Dropped the store of the current instance');
});
// 呼叫時,若引數為一個指定了 name 和 storeName 屬性的物件,會刪除指定的 “資料倉庫”。
localforage.dropInstance({ name: "otherName", storeName: "otherStore" })
.then(function() {
console.log('Dropped otherStore');
});
// 呼叫時,若引數為一個僅指定了 name 屬性的物件,將刪除指定的 “資料庫” (及其所有資料倉庫)。
localforage.dropInstance({ name: "otherName" })
.then(function() {
console.log('Dropped otherName database');
});
|
idb-keyval
idb-keyval 是用 IndexedDB 實現的一個超級簡單的基於 promise 的鍵值儲存。
安裝
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // 全部引入
import idbKeyval from 'idb-keyval';
idbKeyval.set('hello', 'world')
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
// 按需引入會 treeshake
import { get, set } from 'idb-keyval';
set('hello', 'world')
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
get('hello')
.then((val) => console.log(val));
|
瀏覽器直接引入:
1
| <script src="https://cdn.jsdelivr.net/npm/idb-keyval@6/dist/umd.js"></script>
|
提供的方法
由於其沒有中文的官網,會把例子及自己的理解附上:
set
set: 設定資料
key 可以是 Number、String、Date(IDB 也允許這些值的陣列,但 IE 不支援)。
value 可以是 Number、Array、Object、Date、Blobs 等,儘管老 Edge 不支援 null。
1
2
3
4
5
| import { set } from 'idb-keyval';
set('hello', 'world')
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
|
setMany
setMany: 設定多個數據
一次設定多個值,比一個一個的設定更快
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import { set, setMany } from 'idb-keyval';
// 不應該:
Promise.all([set(123, 456), set('hello', 'world')])
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
// 這樣做更快:
setMany([
[123, 456],
['hello', 'world'],
])
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
|
get
get: 獲取資料
如果沒有 key,那麼 value 將返回 undefined。
1
2
3
4
5
| import { get } from 'idb-keyval';
// logs: "world"
get('hello')
.then((val) => console.log(val));
|
getMany
getMany: 獲取多個數據
一次獲取多個數據,比一個一個的獲取資料更快
1
2
3
4
5
6
7
8
9
| import { get, getMany } from 'idb-keyval';
// 不應該:
Promise.all([get(123), get('hello')])
.then(([firstVal, secondVal]) => console.log(firstVal, secondVal));
// 這樣做更快:
getMany([123, 'hello'])
.then(([firstVal, secondVal]) => console.log(firstVal, secondVal));
|
del
del: 刪除資料
根據 key 刪除資料
1
2
3
| import { del } from 'idb-keyval';
del('hello');
|
delMany
delMany: 刪除多個數據
一次刪除多個鍵,比一個一個的刪除更快
1
2
3
4
5
6
7
8
9
10
11
12
| import { del, delMany } from 'idb-keyval';
// 不應該:
Promise
.all([del(123), del('hello')])
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
// 這樣做更快:
delMany([123, 'hello'])
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
|
update
update: 排隊更新資料,防止由於非同步導致資料更新問題
因為 get 與 set 都是非同步的使用他們來更新資料可能會存在問題如:
1
2
3
4
5
6
|
// Don't do this:
import { get, set } from 'idb-keyval';
get('counter').then((val) => set('counter', (val || 0) + 1); );
get('counter').then((val) => set('counter', (val || 0) + 1); );
// 上述程式碼我們期望的是 2 但實際結果是 1,我們可以在第一個 callback 執行第二次操作。
|
更好的方法是使用 update 來更新資料:
1
2
3
4
5
6
| // Instead:
import { update } from 'idb-keyval';
update('counter', (val) => (val || 0) + 1);
update('counter', (val) => (val || 0) + 1);
// 將自動排隊更新,所以第一次更新將計數器設定為 1,第二次更新將其設定為 2。
|
clear
clear: 清除所有資料
1
2
3
| import { clear } from 'idb-keyval';
clear();
|
entries
entries: 返回 [key, value] 形式的資料
1
2
3
4
| import { entries } from 'idb-keyval';
// logs: [[123, 456], ['hello', 'world']]
entries().then((entries) => console.log(entries));
|
keys
keys: 獲取所有資料的 key
1
2
3
4
| import { keys } from 'idb-keyval';
// logs: [123, 'hello']
keys().then((keys) => console.log(keys));
|
values
values: 獲取所有資料的 value
1
2
3
4
| import { values } from 'idb-keyval';
// logs: [456, 'world']
values().then((values) => console.log(values));
|
createStore
createStore: 自定義倉庫
1
2
3
4
5
6
7
8
9
10
11
| // 自定義資料庫名稱及表名稱
// 建立一個數據庫:
// 資料庫名稱為 tang_shi,表名為 table1
const tang_shi_table1 = idbKeyval.createStore('tang_shi', 'table1');
// 向對應倉庫新增資料
idbKeyval.set('add', 'table1 的資料', tang_shi_table1);
// 預設建立的倉庫名稱為 keyval-store,表名為 keyval
idbKeyval.set('add', '預設的資料');
|

使用 createStore 建立的資料庫一個庫只會建立一個表:
1
2
3
4
5
6
7
| // 同一個庫有不可以有兩個表,custom-store-2 不會建立成功:
const customStore = createStore('custom-db-name', 'custom-store-name');
const customStore2 = createStore('custom-db-name', 'custom-store-2');
// 不同的庫有相同的表名,這是可以的:
const customStore3 = createStore('db3', 'keyval');
const customStore4 = createStore('db4', 'keyval');
|
總結
本文介紹了兩個 IndexedDB 的庫,用來解決 localStorage 儲存容量太小的問題。
localforage 與 idb-keyval 之間我更喜歡 localforage 因為其與 localStorage 相似的 api 幾乎沒有上手成本。
如果需要更加靈活的庫可以看一下 dexie.js、PouchDB、idb、JsStore 或者 lovefield 之類的庫。