基于 localStorage 实现一个具有过期时间的 DAO 库

简介: 本文主要解决原生localStorage无法设置过期时间的问题,并通过封装,来实现一个操作便捷,功能强大的localStorage库,关于库封装的一些基本思路和模式,我将采用之前写的如何用不到200行代码写一款属于自己的js类库中类似的方法,感兴趣的朋友可以学习,交流。

本文主要解决原生localStorage无法设置过期时间的问题,并通过封装,来实现一个操作便捷,功能强大的localStorage库,关于库封装的一些基本思路和模式,我将采用之前写的如何用不到200行代码写一款属于自己的js类库中类似的方法,感兴趣的朋友可以学习,交流。


设计思路


我们将基于localStorage原始api进行扩展,让其支持失效时间,操作完成后的回调。在文章的最后,我将给出库的完成代码,接下来我们就一步步实现吧。


正文


  1. 首先,我们来设计库的基本框架:


constBaseStorage=function(preId, timeSign){
// 初始化一些操作 }
BaseStorage.prototype= {
storage: localStorage||window.localStorage,
set: function(key, value, cb, time){
   },
get: function(key, cb){
   },
// 删除storage,如果删除成功,返回删除的内容remove: function(key, cb){
   }
 }

如上可以发现,我们的storage会有三个核心api,分别为set,get,remove,我们使用localStorage作为基础库支持,当然你也可以将上面的库换成sessionStorage或者其他。


  1. 有了基本骨架,我们就可以实现基本功能的封装,这里我们先在原型中加一个属性,来列出数据操作中的各个状态。


status: {
SUCCESS: 0, // 成功FAILURE: 1, // 失败OVERFLOW: 2, // 数据溢出TIMEOUT: 3// 超时},

为了实现过期时间,我们有两种思路,第一种是先将一个过期时间存到storage中,每次操作都检查一遍是否过期,但是这种方案意味着对不同的键就要设置不同的过期时间的storage与之对应,这样会占用额外的库内存,维护起来也不方便。另一种方法就是将过期时间存放到键值中,将时间和值通过标识符分隔,每次取的时候从值中截取过期时间,再将真实的值取出来返回,这种方案不会添加额外的键值对存储,维护起来也相对简单,所以我们采用这种方案。 为了区分不同的库对象,我们还可以添加键前缀,如下:


constBaseLocalStorage=function(preId, timeSign){
this.preId=preId; // 键前缀this.timeSign=timeSign||'|-|';  // 过期时间和值的分隔符 }

基于这个思想,我们就可以接下来的实现了。


  • getKey——修饰key的方法,不影响用户对真实key的影响
getKey: function(key){
returnthis.preId+key   },
  • set实现
set: function(key, value, cb, time){
varstatus=this.status.SUCCESS,
key=this.getKey(key);
// 设置失效时间,未设置时间默认为一个月try{
time=newDate(time).getTime() ||time.getTime();
     }catch(e){
time=newDate().getTime() +1000*60*60*24*31     }
try{
this.storage.setItem(key, time+this.timeSign+value);
     }catch(e){
status=this.status.OVERFLOW;
     }
// 操作完成后的回调cb&&cb.call(this, status, key, value)
   }
  • get实现
get: function(key, cb){
varstatus=this.status.SUCCESS,
key=this.getKey(key),
value=null,
timeSignLen=this.timeSign.length,
that=this,
index,
time,
result;
try{
value=that.storage.getItem(key);
     }catch(e){
result= {
status: that.status.FAILURE,
value: null       }
cb&&cb.call(this, result.status, result.value);
returnresult     }
if(value) {
index=value.indexOf(that.timeSign);
time=+value.slice(0, index);
// 判断是否过期,过期则清除if(time>newDate().getTime() ||time==0){
value=value.slice(index+timeSignLen);
       }else{
value=null,
status=that.status.TIMEOUT;
that.remove(key);
       }
     }else{
status=that.status.FAILURE;
     }
result= {
status: status,
value: value     };
cb&&cb.call(this, result.status, result.value);
returnresult   }
  • remove实现
// 删除storage,如果删除成功,返回删除的内容remove: function(key, cb){
varstatus=this.status.FAILURE,
key=this.getKey(key),
value=null;
try{
value=this.storage.getItem(key);
     }catch(e){
// dosomething     }
if(value){
try{
this.storage.removeItem(key);
status=this.status.SUCCESS;
       }catch(e){
// dosomething       }
     }
cb&&cb.call(this, status, status>0?null : value.slice(value.indexOf(this.timeSign) +this.timeSign.length))
   }

在api的实现过程中,由于某种误操作很可能导致storage报错,所以建议最好用trycatch包裹,这样可以避免影响后面的逻辑。


接下来我们可以这么使用:

leta=newBaseStorage('_', '@');
a.set('name', '123')
a.get('name') // {status: 0, value: "123"}// 设置失效时间a.set('name', '123', null, newDate().getTime() +1000*60*60*24*31)
// 移除a.remove('name')

完整源码

/** * 数据管理器 */(function(win){
constBaseStorage=function(preId, timeSign){
this.preId=preId;
this.timeSign=timeSign||'|-|';
  }
BaseStorage.prototype= {
status: {
SUCCESS: 0,
FAILURE: 1,
OVERFLOW: 2,
TIMEOUT: 3    },
storage: localStorage||window.localStorage,
getKey: function(key){
returnthis.preId+key    },
set: function(key, value, cb, time){
varstatus=this.status.SUCCESS,
key=this.getKey(key);
// 设置失效时间,未设置时间默认为一个月try{
time=newDate(time).getTime() ||time.getTime();
      }catch(e){
time=newDate().getTime() +1000*60*60*24*31      }
try{
this.storage.setItem(key, time+this.timeSign+value);
      }catch(e){
status=this.status.OVERFLOW;
      }
cb&&cb.call(this, status, key, value)
    },
get: function(key, cb){
varstatus=this.status.SUCCESS,
key=this.getKey(key),
value=null,
timeSignLen=this.timeSign.length,
that=this,
index,
time,
result;
try{
value=that.storage.getItem(key);
      }catch(e){
result= {
status: that.status.FAILURE,
value: null        }
cb&&cb.call(this, result.status, result.value);
returnresult      }
if(value) {
index=value.indexOf(that.timeSign);
time=+value.slice(0, index);
if(time>newDate().getTime() ||time==0){
value=value.slice(index+timeSignLen);
        }else{
value=null,
status=that.status.TIMEOUT;
that.remove(key);
        }
      }else{
status=that.status.FAILURE;
      }
result= {
status: status,
value: value      };
cb&&cb.call(this, result.status, result.value);
returnresult    },
// 删除storage,如果删除成功,返回删除的内容remove: function(key, cb){
varstatus=this.status.FAILURE,
key=this.getKey(key),
value=null;
try{
value=this.storage.getItem(key);
      }catch(e){
// dosomething      }
if(value){
try{
this.storage.removeItem(key);
status=this.status.SUCCESS;
        }catch(e){
// dosomething        }
      }
cb&&cb.call(this, status, status>0?null : value.slice(value.indexOf(this.timeSign) +this.timeSign.length))
    }
  }
win.BS=BaseStorage;
})(window)

大家也可以基于此扩展更强大的功能,如果有更好的想法,欢迎交流,探讨。

目录
相关文章
|
数据可视化 大数据 物联网
【专访蓝景科技】5G+实时云渲染赋能数字孪生,共建元宇宙
而同时,近年来,数字孪生技术被认为是具有战略性、颠覆性、先导性的技术,其应用场景已深入到城市治理、智慧园区、工业制造、医疗健康等新型智慧城市建设的方方面面,随着“探索建设数字孪生城市”被写入“十四五”规划纲要中,数字孪生技术已成为是构建新型智慧城市的重要技术手段。元宇宙和数字孪生都是信息化发展到一定程度的必然结果,二者之间既有不同之处,又深度融合。
【专访蓝景科技】5G+实时云渲染赋能数字孪生,共建元宇宙
|
资源调度 前端开发 JavaScript
lowcode-cms开源社区源码设计分享
lowcode-cms开源社区源码设计分享
308 3
lowcode-cms开源社区源码设计分享
|
算法 API 开发工具
ArcFace
ArcFace 是虹软公司开发的一款人脸识别 SDK,它具有高性能、高精度、高鲁棒性等特点,支持多种人脸检测、识别和跟踪技术,可用于多种场景,如手机解锁、身份认证、人脸支付等。
553 1
|
缓存 分布式计算 前端开发
从npm版本依赖到Monorepo大仓项目
前端的发展很快,自从node.js的出现,打开前端新的大门,npm让js有了自己的包管理能力,能够让前端项目工程化,从而能够处理更加复杂的前端项目。
441 0
|
前端开发 搜索推荐 数据可视化
阿里低代码引擎 LowCodeEngine 正式开源!
低代码引擎是一款为低代码平台开发者提供的,具备强大扩展能力的低代码研发框架。
2736 0
阿里低代码引擎 LowCodeEngine 正式开源!
|
弹性计算 运维 监控
基于云监控实现的监控系统
通过阿里云云监控功能给非阿里云主机安装监控插件,从而实现对非阿里云主机的各项指标进行监控和管理,在配置报警规则和报警人的情况下,能对特定的场景做出报警反应通知到报警人的手机上。
|
前端开发 Java Spring
《Spring MVC》 第十章 使用logback+Slf4j打印日志
《Spring MVC》 第十章 使用logback+Slf4j打印日志
379 0
|
存储 数据可视化 前端开发
这款国外开源框架, 让你轻松构建自己的页面编辑器
前段时间我一直在设计和研究低代码搭建平台,也开源了几款可视化编辑器框架,最近在 github 上发现了一款非常强大的基于自然流布局的页面搭建框架 GrapesJS,接下来我就带大家摸索一下这款框架。
823 0
|
JavaScript 前端开发 API
原生javascript组件开发之Web Component实战
作为一名前端工程师,我们每天都在和组件打交道,我们也许基于react/vue使用过很多第三方组件库,比如ant design,elementUI,iView等,或者基于它们进行过组件的二次开发,比如业务组件,UI组件等,亦或者觉得团队能力很强,可以不依赖第三方而独立开发属于自己的组件库。无论何种形式,组件开发已然成为我们工作中的必备技能,为了更好的复用性和可维护性,组件化开发是必然选择,也正是因为组件化开发越来越重要,几年前web标准推出了Web Component这一概念,意在解决html原生标记语言复用性的问题。
1146 0
|
JSON 资源调度 前端开发
从0到1教你搭建前端团队的组件系统(高级进阶必备)
随着vue/react这类以数据驱动为主的web框架的不断完善和壮大,越来越多的前端团队开始着手搭建内部的组件库。虽然目前市面上已经有很多功能强大且完善的组件库供我们使用,比如基于react的开源组件库ant-design,material,又比如基于vue的开源组件库elementUI,iView等。
994 0