一、不足之处
经常用localStorage的朋友可能都知道,它是一种在用户浏览器中存储数据的机制。虽然它很有用,但也存在一些不足之处:
1.存储数据类型限制
localStorage只能存储字符串类型。这意味着我想要存储对象等数据,还需要使用JSON.stringify()
方法将其转换为字符串,在读取数据时,再使用JSON.parse()
方法将字符串转换回原来的数据类型。 同时如果我存储的是数字100
,读取出来的却是字符串'100'
,这就改变了原有数据类型了。
2.存储数据明文易暴露
因为localStorage在浏览器中存储的是未经任何处理的明文,任何具有访问该浏览器权限的人都可以查看和修改这些数据。这对于存储敏感信息(如用户密码、信用卡号等)来说是非常不安全的。
3.数据同步不方便
对于一个需要频繁同步状态到本地存储的应用,localStorage经常需要处理数据的格式转换和存取。当变量的状态变化多了,每次都要在变量状态变化后调用方法同步这个变化到存储中,显得并不那么方便。
4.跨标签页数据无法实时同步
如果用户开启多个标签页,不经意间将其中一个标签页localStorage中设置改变了,其他标签页无法实时得知变化。这就造成了业务逻辑可能按旧值运行,造成业务逻辑的混乱。
二、 解决方案
基于以上几点,我开始设想构建一个库(liveStorage),它可以操作locolStorage``sessionStorage``cookie
等存储媒介,同时解决以上4点不足之处。基于此,我挨个介绍下这个库的处理方式。
1.解决存储数据类型限制
解决数据类型限制最主要的步骤就对不同数据进行识别标识,再经过序列号处理后存储,当读取的时候根据标识逆向还原即可。 由于对象的值和数组的元素存在诸多不可被直接序列号的值,想要存储需要遍历值,将字面量特殊处理后再将对象进行序列号。对象的处理需要递归进行,因为难保某个对象值本身就是对象。
Number
,BigInt
,Boolean
,RegExp
,Date
,Symbol
等类型可以直接调用toString方法序列号; Map
类型可以直接调用Array.from转化成数组;Undefined
,Null
直接用字符串代替即可。
2.解决明文暴露问题
将序列化玩的明文通过一系列自定义的编码操作进行'加密'。前端的加密虽然并不是绝对安全的,但它在一定程度上提高了对方直接破解的难度。同时可以添加多层转码操作,增加其复杂性。 对此,我以下几层简单的编码方式:
encodeURIComponent
和decodeURIComponent
实现中文字符编码和ASCII字符序列转换;
btoa
和atob
实现ASCII字符序列和Base64字符串转换;
以上两组方法为语言内置的转码函数,比较容易被猜测出来,还需要内部添加动态化的词典再次做映射等处理,这样确保不那么快被猜出来。
3.实现数据同步问题
对于数据同步,最轻松的方式还是能像React和Vue那样的数据响应式,通过Proxy对数据进行代理,开发者对数据状态进行变化的时候即可通过代理的setter方法自动调用内部方法,实时将数据同步到本地存储中。在Vue中rel()直接将数据进行响应式处理,而我调用自己的watchItem()方法也对数据进行响应式处理并已经直接和locaLStorage进行绑定了。可以说它打通了三端的关联:数据、节点和localStorage。
javascript
// 和input进行数据双向绑定,同时同步到本地存储(localStorage)中
let data = liveStorage.watchItem('username','Michael',{
'mount':'input[name="username"]'
});
// 改变数据的值,即可实时更新本地存储(localStorage)
data.value = 'Jafferson';
由于直接量无法进行代理,可以将此赋值到临时对象中,用.value访问,这样就解决了代理的问题了。(用惯了Vue的孩子们都懂的,直接量需要用.value访问)
4.多标签页间数据同步方案
localStorage仅有方法调用,常规的使用中缺少事件驱动。我们需要增加事件处理,通知每个标签页本地存储中的数据变动了,让它们及时更新状态。
因为localStorage和sessionStorage都是Storage的实例化对象,可以通过storage事件监听其变化。
javascript
window.addEventListener('storage',function(event){
...
});
传统的cookie是通过document.cookie进行操作的,并没有直接的事件,但现在已经有新的操作cookie的方式啦!
cookieStore
是现代 JavaScript 中用于操作浏览器 Cookie 的 API ,它在浏览器环境中提供了一种更为灵活和强大的方式来管理 Cookie。cookieStore可以通过change事件监听cookie内容变化。
javascript
cookieStore.addEventListener('change',function(event){
...
});
对于数据在多标签中同步的好处,我写了一个简单的Demo,你可以同时打开多个标签页,修改表单项。看其他标签页中表单项是否可以实时变化。 多标签页数据变化演示
三、 我的开源项目
开源仓库:github.com/mumuy/lives...