參考網站
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 之類的庫。