彌補(bǔ)localStorage容量缺陷方法詳解
正文
localStorage 是前端本地存儲的一種,其容量一般在 5M-10M 左右,用來緩存一些簡單的數(shù)據(jù)基本夠用,畢竟定位也不是大數(shù)據(jù)量的存儲。
在某些場景下 localStorage 的容量就會有點(diǎn)捉襟見肘,其實瀏覽器是有提供大數(shù)據(jù)量的本地存儲的如 IndexedDB 存儲數(shù)據(jù)大小一般在 250M 以上。
彌補(bǔ)了localStorage容量的缺陷,但是使用要比localStorage復(fù)雜一些 mdn IndexedDB
不過已經(jīng)有大佬造了輪子封裝了一些調(diào)用過程使其使用相對簡單,下面我們一起來看一下
localforage
localforage 擁有類似 localStorage API,它能存儲多種類型的數(shù)據(jù)如 Array ArrayBuffer Blob Number Object String,而不僅僅是字符串。
這意味著我們可以直接存 對象、數(shù)組類型的數(shù)據(jù)避免了 JSON.stringify 轉(zhuǎn)換數(shù)據(jù)的一些問題。
存儲其他數(shù)據(jù)類型時需要轉(zhuǎn)換成上邊對應(yīng)的類型,比如vue3中使用 reactive 定義的數(shù)據(jù)需要使用toRaw 轉(zhuǎn)換成原始數(shù)據(jù)進(jìn)行保存, ref 則直接保存 xxx.value 數(shù)據(jù)即可。
安裝
下載最新版本 或使用 npm bower 進(jìn)行安裝使用。
# 引入下載的 localforage 即可使用
<script src="localforage.js"></script>
<script>console.log('localforage is: ', localforage);</script>
# 通過 npm 安裝:
npm install localforage
# 或通過 bower:
bower install localforage
使用
提供了與 localStorage 相同的api,不同的是它是異步的調(diào)用返回一個 Promise 對象
localforage.getItem('somekey').then(function(value) {
// 當(dāng)離線倉庫中的值被載入時,此處代碼運(yùn)行
console.log(value);
}).catch(function(err) {
// 當(dāng)出錯時,此處代碼運(yùn)行
console.log(err);
});
// 回調(diào)版本:
localforage.getItem('somekey', function(err, value) {
// 當(dāng)離線倉庫中的值被載入時,此處代碼運(yùn)行
console.log(value);
});
提供的方法有
getItem 根據(jù)數(shù)據(jù)的 key 獲取數(shù)據(jù) 差不多返回 null
setItem 根據(jù)數(shù)據(jù)的 key 設(shè)置數(shù)據(jù)(存儲undefined時getItem獲取會返回 null)
removeItem 根據(jù)key刪除數(shù)據(jù)
length 獲取key的數(shù)量
key 根據(jù) key 的索引獲取其名
keys 獲取數(shù)據(jù)倉庫中所有的 key。
iterate 迭代數(shù)據(jù)倉庫中的所有 value/key 鍵值對。
配置
完整配置可查看文檔 這里說個作者覺得有用的
localforage.config({ name: 'My-localStorage' }); 設(shè)置倉庫的名字,不同的名字代表不同的倉庫,當(dāng)一個應(yīng)用需要多個本地倉庫隔離數(shù)據(jù)的時候就很有用。
const store = localforage.createInstance({
name: "nameHere"
});
const otherStore = localforage.createInstance({
name: "otherName"
});
// 設(shè)置某個數(shù)據(jù)倉庫 key 的值不會影響到另一個數(shù)據(jù)倉庫
store.setItem("key", "value");
otherStore.setItem("key", "value2");
同時也支持刪除倉庫
// 調(diào)用時,若不傳參,將刪除當(dāng)前實例的 “數(shù)據(jù)倉庫” 。
localforage.dropInstance().then(function() {
console.log('Dropped the store of the current instance').
});
// 調(diào)用時,若參數(shù)為一個指定了 name 和 storeName 屬性的對象,會刪除指定的 “數(shù)據(jù)倉庫”。
localforage.dropInstance({
name: "otherName",
storeName: "otherStore"
}).then(function() {
console.log('Dropped otherStore').
});
// 調(diào)用時,若參數(shù)為一個僅指定了 name 屬性的對象,將刪除指定的 “數(shù)據(jù)庫”(及其所有數(shù)據(jù)倉庫)。
localforage.dropInstance({
name: "otherName"
}).then(function() {
console.log('Dropped otherName database').
});
idb-keyval
idb-keyval是用IndexedDB實現(xiàn)的一個超級簡單的基于 promise 的鍵值存儲。
安裝
npm
npm install idb-keyval
// 全部引入
import idbKeyval from 'idb-keyval';
idbKeyval.set('hello', 'world')
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
// 按需引入會搖樹
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));
瀏覽器直接引入 <script src="https://cdn.jsdelivr.net/npm/idb-keyval@6/dist/umd.js"></script>
暴露的全局變量是 idbKeyval 直接使用即可。
提供的方法
由于其沒有中文的官網(wǎng),會把例子及自己的理解附上
set 設(shè)置數(shù)據(jù)
值可以是 數(shù)字、數(shù)組、對象、日期、Blobs等,盡管老Edge不支持null。
鍵可以是數(shù)字、字符串、日期,(IDB也允許這些值的數(shù)組,但I(xiàn)E不支持)。
import { set } from 'idb-keyval';
set('hello', 'world')
.then(() => console.log('It worked!'))
.catch((err) => console.log('It failed!', err));
setMany 設(shè)置多個數(shù)據(jù)
一個設(shè)置多個值,比一個一個的設(shè)置更快
import { set, setMany } from 'idb-keyval';
// 不應(yīng)該:
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 獲取數(shù)據(jù)
如果沒有鍵,那么val將返回undefined的。
import { get } from 'idb-keyval';
// logs: "world"
get('hello').then((val) => console.log(val));
getMany 獲取多個數(shù)據(jù)
一次獲取多個數(shù)據(jù),比一個一個獲取數(shù)據(jù)更快
import { get, getMany } from 'idb-keyval';
// 不應(yīng)該:
Promise.all([get(123), get('hello')]).then(([firstVal, secondVal]) =>
console.log(firstVal, secondVal),
);
// 這樣做更快:
getMany([123, 'hello']).then(([firstVal, secondVal]) =>
console.log(firstVal, secondVal),
);
del 刪除數(shù)據(jù)
根據(jù) key 刪除數(shù)據(jù)
import { del } from 'idb-keyval';
del('hello');
delMany 刪除多個數(shù)據(jù)
一次刪除多個鍵,比一個一個刪除要快
import { del, delMany } from 'idb-keyval';
// 不應(yīng)該:
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 排隊更新數(shù)據(jù),防止由于異步導(dǎo)致數(shù)據(jù)更新問題
因為 get 與 set 都是異步的使用他們來更新數(shù)據(jù)可能會存在問題如:
// 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 但實際結(jié)果是 1,我們可以在第一個回調(diào)執(zhí)行第二次操作。
更好的方法是使用 update 來更新數(shù)據(jù)
// Instead:
import { update } from 'idb-keyval';
update('counter', (val) => (val || 0) + 1);
update('counter', (val) => (val || 0) + 1);
將自動排隊更新,所以第一次更新將計數(shù)器設(shè)置為1,第二次更新將其設(shè)置為2。
clear 清除所有數(shù)據(jù)
import { clear } from 'idb-keyval';
clear();
entries 返回 [key, value] 形式的數(shù)據(jù)
import { entries } from 'idb-keyval';
// logs: [[123, 456], ['hello', 'world']]
entries().then((entries) => console.log(entries));
keys 獲取所有數(shù)據(jù)的 key
import { keys } from 'idb-keyval';
// logs: [123, 'hello']
keys().then((keys) => console.log(keys));
values 獲取所有數(shù)據(jù) value
import { values } from 'idb-keyval';
// logs: [456, 'world']
values().then((values) => console.log(values));
createStore 自定義倉庫
文字解釋:表 === store === 商店 一個意思
// 自定義數(shù)據(jù)庫名稱及表名稱
// 創(chuàng)建一個數(shù)據(jù)庫: 數(shù)據(jù)庫名稱為 tang_shi, 表名為 table1
const tang_shi_table1 = idbKeyval.createStore('tang_shi', 'table1')
// 向?qū)?yīng)倉庫添加數(shù)據(jù)
idbKeyval.set('add', 'table1 的數(shù)據(jù)', tang_shi_table1)
// 默認(rèn)創(chuàng)建的倉庫名稱為 keyval-store 表名為 keyval
idbKeyval.set('add', '默認(rèn)的數(shù)據(jù)')

使用 createStore 創(chuàng)建的數(shù)據(jù)庫一個庫只會創(chuàng)建一個表即:
// 同一個庫有不可以有兩個表,custom-store-2 不會創(chuàng)建成功:
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');
promisifyRequest
自己管理定制商店,這個沒搞太明白,看文檔中說既然都用到這個了不如直接使用idb 這個庫
總結(jié)
本文介紹了兩個 IndexedDB 的庫,用來解決 localStorage 存儲容量太小的問題
localforage 與 idb-keyval 之間我更喜歡 localforage 因為其與 localStorage 相似的api幾乎沒有上手成本。
如果需要更加靈活的庫可以看一下 dexie.js、PouchDB、idb、JsStore 或者 lovefield 之類的庫
以上就是彌補(bǔ)localStorage容量缺陷方法詳解的詳細(xì)內(nèi)容,更多關(guān)于localStorage容量缺陷的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript必知必會(三) String .的方法來自何方
這篇文章主要介紹了JavaScript必知必會(三) String .的方法來自何方的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-06
JavaScript中函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別詳解
可能很多朋友只知道兩種聲明方式一個是函數(shù)聲明一個是函數(shù)表達(dá)式,具體有什么不同沒能說得很好。事實上,JavaScript的解析器對函數(shù)聲明與函數(shù)表達(dá)式并不是一視同仁地對待的。下面看看這兩者到底有什么不同。2016-08-08
用js控制組織結(jié)構(gòu)圖可以任意拖拽到指定位置
用js控制生成了一個組織結(jié)構(gòu)圖并設(shè)置這個組織結(jié)構(gòu)可以任意拖動到指定位置,具體代碼如下2014-01-01

