localStorage容量太小?试试它们

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

原文链接: https://juejin.cn/post/7163075131261059086

作者:唐诗

localStorage 是前端本地存储的一种,其容量一般在 5M-10M 左右,用来缓存一些简单的数据基本够用,毕竟定位也不是大数据量的存储。

在某些场景下 localStorage 的容量就会有点捉襟见肘,其实浏览器是有提供大数据量的本地存储的如 IndexedDB 存储数据大小一般在 250M 以上。

弥补了localStorage容量的缺陷,但是使用要比localStorage复杂一些 mdn IndexedDB[1]

不过已经有大佬造了轮子封装了一些调用过程使其使用相对简单,下面我们一起来看一下

localforage

localforage[2] 拥有类似 localStorage API,它能存储多种类型的数据如 **Array ArrayBuffer Blob Number Object String**,而不仅仅是字符串。

这意味着我们可以直接存 对象、数组类型的数据避免了 JSON.stringify 转换数据的一些问题。

存储其他数据类型时需要转换成上边对应的类型,比如vue3中使用 reactive 定义的数据需要使用toRaw 转换成原始数据进行保存, ref 则直接保存 xxx.value 数据即可。

安装

下载最新版本[3] 或使用 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,不同的是它是异步的调用返回一个 Promise 对象

localforage.getItem('somekey').then(function(value) {
    // 当离线仓库中的值被载入时,此处代码运行
    console.log(value);
}).catch(function(err) {
    // 当出错时,此处代码运行
    console.log(err);
});

// 回调版本:
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 键值对。

配置

完整配置可查看文档[4] 这里说个作者觉得有用的

localforage.config({ name: 'My-localStorage' }); 设置仓库的名字,不同的名字代表不同的仓库,当一个应用需要多个本地仓库隔离数据的时候就很有用。

const store = localforage.createInstance({
    name: "nameHere"
});

const otherStore = localforage.createInstance({
    name: "otherName"
});

// 设置某个数据仓库 key 的值不会影响到另一个数据仓库
store.setItem("key", "value");
otherStore.setItem("key", "value2");

同时也支持删除仓库

// 调用时,若不传参,将删除当前实例的 “数据仓库” 。
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 的键值存储。

安装

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 直接使用即可。

提供的方法

由于其没有中文的官网,会把例子及自己的理解附上

set 设置数据

值可以是 数字、数组、对象、日期、Blobs等,尽管老Edge不支持null。

键可以是数字、字符串、日期,(IDB也允许这些值的数组,但IE不支持)。

import { set } from 'idb-keyval';

set('hello', 'world')
  .then(() => console.log('It worked!'))
  .catch((err) => console.log('It failed!', err));

setMany 设置多个数据

一个设置多个值,比一个一个的设置更快

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 获取数据

如果没有键,那么val将返回undefined的。

import { get } from 'idb-keyval';

// logs: "world"
get('hello').then((val) => console.log(val));

getMany 获取多个数据

一次获取多个数据,比一个一个获取数据更快

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 删除数据

根据 key 删除数据

import { del } from 'idb-keyval';

del('hello');

delMany 删除多个数据

一次删除多个键,比一个一个删除要快

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 排队更新数据,防止由于异步导致数据更新问题

因为 getset 都是异步的使用他们来更新数据可能会存在问题如:

// 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,我们可以在第一个回调执行第二次操作。

更好的方法是使用 update 来更新数据

// Instead:
import { update } from 'idb-keyval';

update('counter', (val) => (val || 0) + 1);
update('counter', (val) => (val || 0) + 1);

将自动排队更新,所以第一次更新将计数器设置为1,第二次更新将其设置为2

clear 清除所有数据

import { clear } from 'idb-keyval';

clear();

entries 返回 [key, value] 形式的数据

import { entries } from 'idb-keyval';

// logs: [[123, 456], ['hello', 'world']]
entries().then((entries) => console.log(entries));

keys 获取所有数据的 key

import { keys } from 'idb-keyval';

// logs: [123, 'hello']
keys().then((keys) => console.log(keys));

values 获取所有数据 value

import { values } from 'idb-keyval';

// logs: [456, 'world']
values().then((values) => console.log(values));

createStore 自定义仓库

文字解释:表 === store === 商店 一个意思

// 自定义数据库名称及表名称
// 创建一个数据库: 数据库名称为 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', '默认的数据')
2ac6d27ebcf517ab0a84f6fbaa8a2474.png
截屏2022-11-06 下午8.40.58.png

使用 createStore 创建的数据库一个库只会创建一个表即:

// 同一个库有不可以有两个表,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');

promisifyRequest

自己管理定制商店,这个没搞太明白,看文档[5]中说既然都用到这个了不如直接使用idb 这个库[6]

总结

本文介绍了两个 IndexedDB 的库,用来解决 localStorage 存储容量太小的问题

localforageidb-keyval 之间我更喜欢 localforage 因为其与 localStorage 相似的api几乎没有上手成本。

如果需要更加灵活的库可以看一下 dexie.js[7]、PouchDB[8]、idb[9]、JsStore[10] 或者 lovefield[11] 之类的库

感谢观看!

参考资料

[1]

https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API: https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API

[2]

https://localforage.docschina.org/#api-config: https://localforage.docschina.org/#api-config

[3]

https://github.com/mozilla/localForage/releases: https://github.com/mozilla/localForage/releases

[4]

https://localforage.docschina.org/#api-config: https://localforage.docschina.org/#api-config

[5]

https://github.com/jakearchibald/idb-keyval/blob/main/custom-stores.md: https://github.com/jakearchibald/idb-keyval/blob/main/custom-stores.md

[6]

https://www.npmjs.com/package/idb: https://www.npmjs.com/package/idb

[7]

https://www.dexie.org/: https://www.dexie.org/

[8]

https://pouchdb.com/: https://pouchdb.com/

[9]

https://www.npmjs.com/package/idb: https://www.npmjs.com/package/idb

[10]

https://jsstore.net/: https://jsstore.net/

[11]

https://github.com/google/lovefield: https://github.com/google/lovefield

Node 社群


我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:

1. 点个「在看」,让更多人也能看到这篇文章2. 订阅官方博客 www.inode.club 让我们一起成长

点赞和在看就是最大的支持❤️
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值