找回密码
 会员注册
查看: 44|回复: 0

聊聊前端存储库localforage和存储配额

[复制链接]

7

主题

0

回帖

22

积分

新手上路

积分
22
发表于 2024-9-20 03:36:06 | 显示全部楼层 |阅读模式
前言浏览器本地存储,是每一个前端小伙伴都相当熟悉的知识点。目前使用率最高的当之无愧为WebStorageAPI,也就是localStorage和sessionStorage,API简单,读取效率高。然后是indexedDB,但大部分时间是存在于八股文和面试题中。indexedDB的优势为存储空间大,且支持各种数据结构,性能也没有问题。之所以不为重用,是因为indexedDB的API多、长且纷杂。另外,前端使用数据库还需要了解一些表、游标、事务等一些概念,对于不了解后端的同学来说上手成本也就高出localStorage太多。所以,在5M内的存储领域,indexedDB并非首选。另外WebSQL已被H5标准放弃,而元老级的Cookie也不再适合现代的客户端存储任务。那么有没有一个既保留indexedDB优点,上手又简单的方法呢,答案就是封装js库,localforage就是一个比较成熟的方案。localforage简介localforage是一个JavaScript库,通过简单类似localStorageAPI的异步存储来改进你的Web应用程序的离线体验。它能存储多种类型的数据,而不仅仅是字符串。localforage采用优雅降级策略,若浏览器不支持indexedDB或WebSQL,则使用localStorage。所以,在优先选用indexedDB存储的前提下,兼容性也得以保证,在所有主流浏览器中都可使用:Chrome,Firefox,IE和Safari(包括SafariMobile)。localforage在github上拥有21.5k个star,npm下载量每周200w左右,正常使用也不会出现问题。用法详细的使用方法不做过多赘述,只讲一下存取示例。setItem// 通过 localForage 完成存储localforage.setItem('key', 'value').then(doSomethingElse); // localForage 同样支持回调函数 localforage.setItem('key', 'value', doSomethingElse);getItemlocalforage.getItem('somekey').then(function(value) {     // 当离线仓库中的值被载入时,此处代码运行     console.log(value); }).catch(function(err) {     // 当出错时,此处代码运行     console.log(err); }); // 回调版本: localforage.getItem('somekey', function(err, value) {     // 当离线仓库中的值被载入时,此处代码运行     console.log(value); });实践在一次的业务需求中,基于以下两点,果断选择了localforage。后期会有大量数据需要本地存储。转转内部有基于localforage.js二次封装的库,且包含设置过期时间的方法,适用于此次需求。上线后的一段时间,该功能平稳运行。直到sentry(错误日志监控系统)出现了大量关于内存溢出的报错......问题处理艰难复现起初怀疑是localforage有兼容性问题,但是localforage有优雅降级机制。再加上报错内容为QuotaExceededError,所以在阅读大量资料后基本锁定为在indexedDB的使用上出现了问题。另外,报错用户数量为个位数,说明了是用户操作或手机存在异常导致的问题。在确定了问题的大体方向,排查代码没有思路的前提下,眼前能做的就是复现这个问题。刚才提到,QuotaExceededError为内存溢出类型报错,直觉告诉我,需要找一个内存空间剩余最少的测试机,但当时最少的也剩余20GB,于是下载了一天大型软件后,终于在内存剩余100MB左右时成功复现。问题原因不同于浏览器会为localStorage预留5MB左右的储存空间,indexedDB的配额是动态计算的,准确的说是浏览器的储存配额是动态计算的,虽然浏览器实现各不相同,但可用存储量通常取决于设备上可用的存储量。这个可用的存储量称为全局限制,Firefox大约为可用磁盘空间的50%,Chrome的这一数据能达到80%。如果超过此范围,则会发起称为源回收的过程,删除整个源的数据,直到存储量再次低于限制。删除源数据没有只删一部分的说法——因为这样可能会导致不一致的问题。除全局限制外,还有另一个限制称为组限制——为全局限制的20%。这里可以把每个二级域名看作一组,每组可以聚合使用最多20%的全局限制。如果超出组限制,或者源回收过程无法释放足够空间,indexedDB或缓存API就会抛出名为QuotaExceededError的DOMError。如何查看有多少可用存储空间?if (navigator.storage & navigator.storage.estimate) {     const quota = await navigator.storage.estimate();     //quota.usage-> 已使用的字节数。    //quota.quota-> 可用最大字节数。    const percentageUsed = (quota.usage / quota.quota) * 100;     console.log(`已使用${percentageUsed}%可用储存。`);     const remaining = quota.quota - quota.usage;     console.log(`最多可再写入${remaining}字节。`); }Ps.这个方法使用了StorageManagerAPI,使用前要先对其进行功能检测。实测过程中,Android的webview支持此方法,ios却不支持。如何解决优雅降级只是去判断了浏览器是否支持某种本地存储的方法,但无法处理硬盘不足的问题,所以如果想去避免这个问题,可以在业务代码中使用try...catch进行异常捕获,手动进行异常处理。业务中常用的解决办法是弹窗提示用户去清理手机硬盘。实测中,华为手机硬盘小于100MB时,系统层也会弹出清理手机的弹窗提示。try {    localforage.setItem('key', 'value', doSomethingElse);} catch(err) {    if (err.name === 'QuotaExceededError') {        //异常处理    }}总结&思考localforage是个优秀的前端存储js库,某种角度来讲,indexedDB的发展要感谢localforage。不论localStorage还是indexedDB,存储空间都受浏览器存储配额的影响,而浏览器的存储配额取决于本地磁盘剩余空间的大小。配额不足就会导致浏览器报QuotaExceededError。开源轮子查问题没思路时,在代码仓库issue中查找会是一个捷径,作者就忽略了这点绕了弯路。参考资料1.https://web.dev/storage-for-the-web/2.https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria3.https://www.zhangxinxu.com/wordpress/2018/06/js-localforage-localstorage-indexdb/
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 12:48 , Processed in 0.543726 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表