给localStorage加上过期时间

17,126 阅读6分钟

一、酷酷的开头

在掘金潜水的时间长达一年之后,我终于鼓起勇气开始写我的第一篇文章了。前端小菜,只是想记录一下自己的想法,望各位看到这文的大佬轻喷。

在现在前后端分离的开发模式下,存储信息一般都不在使用以往使用的cookie了,就拿笔主我之前做过的项目来说。我们都是登录成功了之后后端会返回给我一个token,一般情况下我会将这个token存到localStorage中,后续再每一次请求中都会将这个token携带在请求头中。 至于为什么要存到localStorage中呢,相信做过单页web应用的开发者们也知道,如果不存着,那用户刷新了就啥都没有了。

可以见得前端存储在项目中是越来越重要了,浏览器给我们提供了两个存储方案,一个是localStorage,一个是sessionStorage。 存到localStorage中的信息是永久存储,如果用户不手动删除或者代码中没有localStorage.removeItem(xxx)这样的调用那这个信息将永远不会消失; 在sessionStorage中存储的信息则是一次性的,用户关掉网页了下一次在进入这个网页信息就不会再存储了。 但是在实际项目的运用中,这两个方案的表现都不是那么令人满意。就比如说,我想要实现用户登录之后七天之内不需要再次登录这样的功能,token生成了之后,后端设置了这个token的过期时间为7天,ok,传到前端, 但是针对浏览器目前提供的存储方案,我却只能选择永久存储和一次性存储。一次性存储肯定是不能满足需求的,永久存储也违背了我的意愿。

二、之前在项目中的解决方案

之前我在项目中的做法是,在用localStorage存储了token值的同时, 我还存了一个过期时间(一个毫秒数),然后在项目初始化的时候我就会去检查这个时间看看是不是已经小于当前时间了,如果是就将token删掉。 这样后续项目在使用到这个token的时候token就已经从localStorage中被删掉了。但是这样做也有一个问题,如果打开项目的时间刚好是还有10s token就过期的话,token也不会被删掉了。于是我脑袋里就在构想一个可(垃)靠(圾)的解决方案,一不做,二不休,我把它封装成了一个工具。

先厚脸皮的介绍一下我的项目, sweet-storage, 请无视这土的要死的名字。 github的地址为:github.com/Chechengyi/…。 顺便也正(卑)大(鄙)光(无)明(耻)的求一波star。

三、提出新的想法

咳咳咳! 废话不多说了,讲一下我的实现思路。

在遇到有过期时间的存储需求时, 用我这个项目举栗子, storage.save('name', 'chechengyi', 10000) 这行代码的意思是我想在localStorage中存一个键为name,值为chechengyi的信息,我希望这条信息只存10s,在将信息存入localStorage中的同时,我会把它的过期时间信息以

  {
      key: time
  }

的形式也存到localStorage中。 key就是键, time就是这条信息到期的时间。 这里的时间的话应该存的是new Date().getTime()+我们设置的时间。这样就得到了一个精确的毫秒数了。 这个过期时间信息在我的项目中以ISTORAGE_RECORD的字段存储。 然后后面我们在根据这里面所提取出来的时间,即:new Date().getTime()-time这个时间去做一个定时器。定时器时间到了就将localStorage中存的信息以及存的时间信息就是那个对象中的key-time删掉就行了。

但是这里也有一个问题,就是。可能我们需要有过期时间存储的时间不只有一条啊。难道存了三条我就做三个定时器?存的100条我就做100个定时器? 这也太low了而且也并不符合实际。于是我冥思苦想,发现我前几天刚学习的优先队列很适合用在这里。

我们可以这样做,基于ISTORAGE_RECORD拿出来的对象里的time去做一个最小堆(我的这个优先队列是基于最小堆的),最小堆嘛,根节点肯定就是最小的,time最小的那个不就是最先执行的定时器吗? 等这个定时器执行时就删掉localStorage里存的信息和时间信息,然后优先队列出列,下一个排队等着出列的元素就是下一个时间最近,等着过期的信息了。这里涉及到了最小堆数据结构的操作就不多讲了。有兴趣的同学可以自己去看看实现。这就是我的项目实现的大概思路, 真正实现的话还要去考虑还没过期就被用户删除了等等的情况。

到这里了我又在想,不行啊,这样过期了也只是“悄悄”的过期了。 我想知道它什么时候过期的,也就是我希望它过期的时候能通知我一声行不行啊? 于是经过我又一轮的冥思苦想,我发现我去年学的发布-订阅模式可以用到这里。然后就是代码实现啦,无非就是做了一个observers对象。 以存储的key名去订阅了一个事件,在我的项目中就是storage.on('name', (key)=>{}) 然后再定时器执行的时候我会observers.trriger('name')去发布这个事件,并且将需要被删除掉的信息的key传入订阅的函数当中。 这样就做到了通知的功能。具体发布-订阅模式怎么实现的也不在此多做赘述了。

四、无耻的总结

sweet-storage 实现的大概思路就说完了,有兴趣的同学可以去看看源码实现,在此强调 github的地址为:github.com/Chechengyi/…。 我的代码写的很通(垃)俗易(圾)懂。

我还将这个项目传到了npm上面, npm install sweet-storage就可以安装到本地。学以致用,这一年多来在各大论坛潜水每次看到别人分享心得心里都痒痒的,这次总算是下定了决心踏出第一步。在这个过程中也学习到了很多,希望自己能够坚持下去。

如果有不对的地方希望朋友们指出,希望朋友们多给我提建议

最后在强调一波!!!

github的地址为:github.com/Chechengyi/…

求star 求fuck......