LocalStorge存大量对象时读写变慢怎么办?
在做电商项目时需要缓存用户浏览过的1000多个商品对象到LocalStorge,发现每次存取都要等几秒。试过用JSON.stringify()序列化,但读取时遍历解析还是卡顿。
代码大概是这样循环存储的:
const items = [];
for (let i = 0; i < 1000; i++) {
items.push({id:i, name:'prod'+i, specs:['S','M','L']});
}
localStorage.setItem('history', JSON.stringify(items));
读取时直接解析后遍历渲染列表就卡死了,控制台显示main thread被阻塞,有没有更好的优化方法?
第一步,优化存储方式。把一千多个对象一次性序列化存储确实会卡,建议改成分块存储。比如每次存100个商品,给每个块起个不同的key,像这样:
第二步,读取时也要分块处理。不要一次性把所有数据都解析出来,而是按需加载。比如用户翻页时只加载当前页需要的数据块:
第三步,考虑使用更高效的存储方案。localStorage本质上是同步阻塞的,而且有5MB的容量限制。可以换成IndexedDB,它是专门设计用来处理大量结构化数据的,支持异步操作,不会阻塞主线程。
这里给你一个简单的IndexedDB封装示例:
最后提醒一下,不管你用哪种方案,都要记得定期清理过期数据。比如只保留最近30天的浏览记录,不然数据量越来越大还是会变慢。
这些方法我都在线上项目中实践过,效果不错。分块存储能显著改善卡顿问题,但长远来看还是建议迁移到IndexedDB,这才是正道。毕竟localStorage本来就是为小数据量设计的,咱们不能强求它干重活。
优化的话可以换个思路,用IndexedDB代替LocalStorage。IndexedDB是专门为存储大量结构化数据设计的,支持异步操作,不会阻塞主线程。下面是个简单的实现:
简单解释一下代码:打开一个叫productHistory的数据库,创建一个products的对象存储空间,直接把商品对象放进去就行,不需要手动序列化。读取的时候用getAll方法一次取出来,效率比LocalStorage高得多。
如果实在不想换存储方式,还有一个折中的办法:分块存储。把1000个商品分成10组,每组100个,分别存在不同的key下,读取时按需加载。但这个方案治标不治本,还是建议用IndexedDB。
顺便吐槽一句,LocalStorage这玩意儿真的该被淘汰了,现代前端开发用它就是给自己挖坑。