彌補(bǔ)localStorage容量缺陷方法詳解
正文
localStorage
是前端本地存儲(chǔ)的一種,其容量一般在 5M-10M
左右,用來(lái)緩存一些簡(jiǎn)單的數(shù)據(jù)基本夠用,畢竟定位也不是大數(shù)據(jù)量的存儲(chǔ)。
在某些場(chǎng)景下 localStorage
的容量就會(huì)有點(diǎn)捉襟見(jiàn)肘,其實(shí)瀏覽器是有提供大數(shù)據(jù)量的本地存儲(chǔ)的如 IndexedDB
存儲(chǔ)數(shù)據(jù)大小一般在 250M
以上。
彌補(bǔ)了localStorage
容量的缺陷,但是使用要比localStorage
復(fù)雜一些 mdn IndexedDB
不過(guò)已經(jīng)有大佬造了輪子封裝了一些調(diào)用過(guò)程使其使用相對(duì)簡(jiǎn)單,下面我們一起來(lái)看一下
localforage
localforage 擁有類似 localStorage
API,它能存儲(chǔ)多種類型的數(shù)據(jù)如 Array
ArrayBuffer
Blob
Number
Object
String
,而不僅僅是字符串。
這意味著我們可以直接存 對(duì)象、數(shù)組類型的數(shù)據(jù)避免了 JSON.stringify
轉(zhuǎn)換數(shù)據(jù)的一些問(wèn)題。
存儲(chǔ)其他數(shù)據(jù)類型時(shí)需要轉(zhuǎn)換成上邊對(duì)應(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> # 通過(guò) npm 安裝: npm install localforage # 或通過(guò) bower: bower install localforage
使用
提供了與 localStorage
相同的api,不同的是它是異步的調(diào)用返回一個(gè) Promise
對(duì)象
localforage.getItem('somekey').then(function(value) { // 當(dāng)離線倉(cāng)庫(kù)中的值被載入時(shí),此處代碼運(yùn)行 console.log(value); }).catch(function(err) { // 當(dāng)出錯(cuò)時(shí),此處代碼運(yùn)行 console.log(err); }); // 回調(diào)版本: localforage.getItem('somekey', function(err, value) { // 當(dāng)離線倉(cāng)庫(kù)中的值被載入時(shí),此處代碼運(yùn)行 console.log(value); });
提供的方法有
getItem
根據(jù)數(shù)據(jù)的 key
獲取數(shù)據(jù) 差不多返回 null
setItem
根據(jù)數(shù)據(jù)的 key
設(shè)置數(shù)據(jù)(存儲(chǔ)undefined
時(shí)getItem獲取會(huì)返回 null
)
removeItem
根據(jù)key刪除數(shù)據(jù)
length
獲取key的數(shù)量
key
根據(jù) key 的索引獲取其名
keys
獲取數(shù)據(jù)倉(cāng)庫(kù)中所有的 key。
iterate
迭代數(shù)據(jù)倉(cāng)庫(kù)中的所有 value/key
鍵值對(duì)。
配置
完整配置可查看文檔 這里說(shuō)個(gè)作者覺(jué)得有用的
localforage.config({ name: 'My-localStorage' });
設(shè)置倉(cāng)庫(kù)的名字,不同的名字代表不同的倉(cāng)庫(kù),當(dāng)一個(gè)應(yīng)用需要多個(gè)本地倉(cāng)庫(kù)隔離數(shù)據(jù)的時(shí)候就很有用。
const store = localforage.createInstance({ name: "nameHere" }); const otherStore = localforage.createInstance({ name: "otherName" }); // 設(shè)置某個(gè)數(shù)據(jù)倉(cāng)庫(kù) key 的值不會(huì)影響到另一個(gè)數(shù)據(jù)倉(cāng)庫(kù) store.setItem("key", "value"); otherStore.setItem("key", "value2");
同時(shí)也支持刪除倉(cāng)庫(kù)
// 調(diào)用時(shí),若不傳參,將刪除當(dāng)前實(shí)例的 “數(shù)據(jù)倉(cāng)庫(kù)” 。 localforage.dropInstance().then(function() { console.log('Dropped the store of the current instance'). }); // 調(diào)用時(shí),若參數(shù)為一個(gè)指定了 name 和 storeName 屬性的對(duì)象,會(huì)刪除指定的 “數(shù)據(jù)倉(cāng)庫(kù)”。 localforage.dropInstance({ name: "otherName", storeName: "otherStore" }).then(function() { console.log('Dropped otherStore'). }); // 調(diào)用時(shí),若參數(shù)為一個(gè)僅指定了 name 屬性的對(duì)象,將刪除指定的 “數(shù)據(jù)庫(kù)”(及其所有數(shù)據(jù)倉(cāng)庫(kù))。 localforage.dropInstance({ name: "otherName" }).then(function() { console.log('Dropped otherName database'). });
idb-keyval
idb-keyval
是用IndexedDB
實(shí)現(xiàn)的一個(gè)超級(jí)簡(jiǎn)單的基于 promise
的鍵值存儲(chǔ)。
安裝
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)); // 按需引入會(huì)搖樹(shù) 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
直接使用即可。
提供的方法
由于其沒(méi)有中文的官網(wǎng),會(huì)把例子及自己的理解附上
set 設(shè)置數(shù)據(jù)
值可以是 數(shù)字、數(shù)組、對(duì)象、日期、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è)置多個(gè)數(shù)據(jù)
一個(gè)設(shè)置多個(gè)值,比一個(gè)一個(gè)的設(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ù)
如果沒(méi)有鍵,那么val
將返回undefined
的。
import { get } from 'idb-keyval'; // logs: "world" get('hello').then((val) => console.log(val));
getMany 獲取多個(gè)數(shù)據(jù)
一次獲取多個(gè)數(shù)據(jù),比一個(gè)一個(gè)獲取數(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 刪除多個(gè)數(shù)據(jù)
一次刪除多個(gè)鍵,比一個(gè)一個(gè)刪除要快
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 排隊(duì)更新數(shù)據(jù),防止由于異步導(dǎo)致數(shù)據(jù)更新問(wèn)題
因?yàn)?get
與 set
都是異步的使用他們來(lái)更新數(shù)據(jù)可能會(huì)存在問(wèn)題如:
// 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
但實(shí)際結(jié)果是 1
,我們可以在第一個(gè)回調(diào)執(zhí)行第二次操作。
更好的方法是使用 update
來(lái)更新數(shù)據(jù)
// Instead: import { update } from 'idb-keyval'; update('counter', (val) => (val || 0) + 1); update('counter', (val) => (val || 0) + 1);
將自動(dòng)排隊(duì)更新,所以第一次更新將計(jì)數(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 自定義倉(cāng)庫(kù)
文字解釋:表 === store === 商店 一個(gè)意思
// 自定義數(shù)據(jù)庫(kù)名稱及表名稱 // 創(chuàng)建一個(gè)數(shù)據(jù)庫(kù): 數(shù)據(jù)庫(kù)名稱為 tang_shi, 表名為 table1 const tang_shi_table1 = idbKeyval.createStore('tang_shi', 'table1') // 向?qū)?yīng)倉(cāng)庫(kù)添加數(shù)據(jù) idbKeyval.set('add', 'table1 的數(shù)據(jù)', tang_shi_table1) // 默認(rèn)創(chuàng)建的倉(cāng)庫(kù)名稱為 keyval-store 表名為 keyval idbKeyval.set('add', '默認(rèn)的數(shù)據(jù)')
使用 createStore
創(chuàng)建的數(shù)據(jù)庫(kù)一個(gè)庫(kù)只會(huì)創(chuàng)建一個(gè)表即:
// 同一個(gè)庫(kù)有不可以有兩個(gè)表,custom-store-2 不會(huì)創(chuàng)建成功: const customStore = createStore('custom-db-name', 'custom-store-name'); const customStore2 = createStore('custom-db-name', 'custom-store-2'); // 不同的庫(kù) 有相同的表名 這是可以的: const customStore3 = createStore('db3', 'keyval'); const customStore4 = createStore('db4', 'keyval');
promisifyRequest
自己管理定制商店,這個(gè)沒(méi)搞太明白,看文檔中說(shuō)既然都用到這個(gè)了不如直接使用idb 這個(gè)庫(kù)
總結(jié)
本文介紹了兩個(gè) IndexedDB
的庫(kù),用來(lái)解決 localStorage
存儲(chǔ)容量太小的問(wèn)題
localforage
與 idb-keyval
之間我更喜歡 localforage
因?yàn)槠渑c localStorage
相似的api幾乎沒(méi)有上手成本。
如果需要更加靈活的庫(kù)可以看一下 dexie.js、PouchDB、idb、JsStore 或者 lovefield 之類的庫(kù)
以上就是彌補(bǔ)localStorage容量缺陷方法詳解的詳細(xì)內(nèi)容,更多關(guān)于localStorage容量缺陷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript必知必會(huì)(三) String .的方法來(lái)自何方
這篇文章主要介紹了JavaScript必知必會(huì)(三) String .的方法來(lái)自何方的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06JS實(shí)用的動(dòng)畫(huà)彈出層效果實(shí)例
這篇文章主要介紹了JS實(shí)用的動(dòng)畫(huà)彈出層效果,實(shí)例分析了javascript實(shí)現(xiàn)動(dòng)畫(huà)效果彈出層的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-05-05jquery 實(shí)現(xiàn)上下滾動(dòng)效果示例代碼
上下滾動(dòng)的效果,不用說(shuō),大家都有看到過(guò),本文為大家介紹下使用jquery實(shí)現(xiàn)上下滾動(dòng)效果,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-08-08JavaScript中函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別詳解
可能很多朋友只知道兩種聲明方式一個(gè)是函數(shù)聲明一個(gè)是函數(shù)表達(dá)式,具體有什么不同沒(méi)能說(shuō)得很好。事實(shí)上,JavaScript的解析器對(duì)函數(shù)聲明與函數(shù)表達(dá)式并不是一視同仁地對(duì)待的。下面看看這兩者到底有什么不同。2016-08-08用js控制組織結(jié)構(gòu)圖可以任意拖拽到指定位置
用js控制生成了一個(gè)組織結(jié)構(gòu)圖并設(shè)置這個(gè)組織結(jié)構(gòu)可以任意拖動(dòng)到指定位置,具體代碼如下2014-01-01