注册

前端比localStorage存储还大的本地存储方案

产品的原话就是“要又大又全”。既然存储量大,也要覆盖全多种设备多种浏览器。


方案选择

  • 既然要存储的数量大,得排除cookie
  • localStorage,虽然比cookie多,但是同样有上限(5M)左右,备选
  • websql 使用简单,存储量大,兼容性差,备选
  • indexDB api多且繁琐,存储量大、高版本浏览器兼容性较好,备选

既然罗列了一些选择,都没有十全十美的,那么有没有一种能够集合这多种方式的插件呢?渐进增强 or 优雅降级 的存在
冲着这个想法,就去github和谷歌找了一下,还真的有这么一个插件。


那就是 localforage


localforage


localForage 是一个 JavaScript 库,只需要通过简单类似 localStorage API 的异步存储来改进你的 Web 应用程序的离线体验。它能存储多种类型的数据,而不仅仅是字符串。 


084e7fcf83f5cf21df26fe88d0605996.png


关于兼容性


localForage 有一个优雅降级策略,若浏览器不支持 IndexedDB 或 WebSQL,则使用 localStorage。在所有主流浏览器中都可用:Chrome,Firefox,IE 和 Safari(包括 Safari Mobile)。下面是 indexDB、web sql、localStorage 的一个浏览器支持情况,可以发现,兼容性方面loaclForage基本上满足99%需求


使用


解决了兼容性和存储量的点,我们就来看看localforage的基础用法


安装

# 通过 npm 安装:
npm install localforage
// 直接引用
<script src="localforage.js"></script>
<script>console.log('localforage is: ', localforage);</script>

获取存储


getItem(key, successCallback)


从仓库中获取 key 对应的值并将结果提供给回调函数。如果 key 不存在,getItem() 将返回 null。

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

// 回调版本:
localforage.getItem('somekey', function(err, value) {
// 当离线仓库中的值被载入时,此处代码运行
console.log(value);
});

设置存储


setItem(key, value, successCallback)


将数据保存到离线仓库。你可以存储如下类型的 JavaScript 对象:

  • Array
  • ArrayBuffer
  • Blob
  • Float32Array
  • Float64Array
  • Int8Array
  • Int16Array
  • Int32Array
  • Number
  • Object
  • Uint8Array
  • Uint8ClampedArray
  • Uint16Array
  • Uint32Array
  • String
localforage
.setItem("somekey", "some value")
.then(function (value) {
// 当值被存储后,可执行其他操作
console.log(value);
})
.catch(function (err) {
// 当出错时,此处代码运行
console.log(err);
});

// 不同于 localStorage,你可以存储非字符串类型
localforage
.setItem("my array", [1, 2, "three"])
.then(function (value) {
// 如下输出 `1`
console.log(value[0]);
})
.catch(function (err) {
// 当出错时,此处代码运行
console.log(err);
});

// 你甚至可以存储 AJAX 响应返回的二进制数据
req = new XMLHttpRequest();
req.open("GET", "/photo.jpg", true);
req.responseType = "arraybuffer";

req.addEventListener("readystatechange", function () {
if (req.readyState === 4) {
// readyState 完成
localforage
.setItem("photo", req.response)
.then(function (image) {
// 如下为一个合法的 <img> 标签的 blob URI
var blob = new Blob([image]);
var imageURI = window.URL.createObjectURL(blob);
})
.catch(function (err) {
// 当出错时,此处代码运行
console.log(err);
});
}
});

删除存储


removeItem(key, successCallback)


从离线仓库中删除 key 对应的值。

localforage.removeItem('somekey').then(function() {
// 当值被移除后,此处代码运行
console.log('Key is cleared!');
}).catch(function(err) {
// 当出错时,此处代码运行
console.log(err);
});

清空存储


clear(successCallback)


从数据库中删除所有的 key,重置数据库。


localforage.clear() 将会删除离线仓库中的所有值。谨慎使用此方法。

localforage.clear().then(function() {
// 当数据库被全部删除后,此处代码运行
console.log('Database is now empty.');
}).catch(function(err) {
// 当出错时,此处代码运行
console.log(err);
});

localforage是否万事大吉?


用上了localforage一开始我也以为可以完全满足万恶的产品了,然而。。。翻车了.。


内存不足的前提下,localforage继续缓存会怎么样?


在这种状态下,尝试使用localforage,不出意外,抛错了 QuotaExceededError 的 DOMErro


解决
存储数据的时候加上存储的时间戳和模块标识,加时间戳一起存储

setItem({
value: '1',
label: 'a',
module: 'a',
timestamp: '11111111111'
})

  • 如果是遇到存储使用报错的情况,try/catch捕获之后,通过判断报错提示,去执行相应的操作,遇到内存不足的情况,则根据时间戳和模块标识清理一部分旧数据(内存不足的情况还是比较少的)
  • 在用户手机上产生脏数据的情况,想要清理的这种情况的 处理方式是:
  • 让后端在用户信息接口里面加上缓存有效期时间戳,当该时间戳存在,则前端会进行一次对本地存储扫描
  • 在有效期时间戳之前的数据,结合模块标识,进行清理,清理完毕后调用后端接口上报清理日志
  • 模块标识的意义是清理数据的时候,可以按照模块去清理(选填)

作者:前端成长指南
链接:https://juejin.cn/post/7273028474973012007
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册