彌補localStorage容量缺陷方法詳解
正文
localStorage
是前端本地存儲的一種,其容量一般在 5M-10M
左右,用來緩存一些簡單的數(shù)據(jù)基本夠用,畢竟定位也不是大數(shù)據(jù)量的存儲。
在某些場景下 localStorage
的容量就會有點捉襟見肘,其實瀏覽器是有提供大數(shù)據(jù)量的本地存儲的如 IndexedDB
存儲數(shù)據(jù)大小一般在 250M
以上。
彌補了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ù)進行保存, ref
則直接保存 xxx.value
數(shù)據(jù)即可。
安裝
下載最新版本 或使用 npm
bower
進行安裝使用。
# 引入下載的 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)離線倉庫中的值被載入時,此處代碼運行 console.log(value); }).catch(function(err) { // 當(dāng)出錯時,此處代碼運行 console.log(err); }); // 回調(diào)版本: localforage.getItem('somekey', function(err, value) { // 當(dāng)離線倉庫中的值被載入時,此處代碼運行 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ù)組,但IE不支持)。
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) // 默認創(chuàng)建的倉庫名稱為 keyval-store 表名為 keyval idbKeyval.set('add', '默認的數(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 之類的庫
以上就是彌補localStorage容量缺陷方法詳解的詳細內(nèi)容,更多關(guān)于localStorage容量缺陷的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript必知必會(三) String .的方法來自何方
這篇文章主要介紹了JavaScript必知必會(三) String .的方法來自何方的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-06JavaScript中函數(shù)聲明與函數(shù)表達式的區(qū)別詳解
可能很多朋友只知道兩種聲明方式一個是函數(shù)聲明一個是函數(shù)表達式,具體有什么不同沒能說得很好。事實上,JavaScript的解析器對函數(shù)聲明與函數(shù)表達式并不是一視同仁地對待的。下面看看這兩者到底有什么不同。2016-08-08用js控制組織結(jié)構(gòu)圖可以任意拖拽到指定位置
用js控制生成了一個組織結(jié)構(gòu)圖并設(shè)置這個組織結(jié)構(gòu)可以任意拖動到指定位置,具體代碼如下2014-01-01