范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

如何让localStorage支持过期时间设置

  前言
  最近在项目开发中,遇见了大家都常会遇见的问题,让本地存储支持过期时间的设置。那相信学习前端的童鞋们都知道,我们经常是会用的 cookie 、localStorage 、sessionStorage ,它们三个都是可以用来存放数据的。这里我们就不细讲它们之间的区别,主要讲当我们设置localStorage 的时候,怎么来给它设置一个过期时间了?下来我们就开始今天的主题。封装
  根据一般的业务需求,我们需要支持`新增,修改,删除`,按照初步设想,开始编写我们代码。可跳过中间部分,直接查看最后的完整版代码示例。(TS目前还有不太熟练的地方,有什么地方有问题欢迎指出)// 定义类 class NStorage {   storage: Storage;   constructor(name?: string) {     this.storage = window[name as keyof typeof window] || window.localStorage   }   /**    * @description 存储方法    * @param {String} key 键名    * @param {any} value 值    * @param {number} [expires] 可选,默认0,永久    */   set(key: string, value: any, expires: number = 0) {     const storeValue = {       value,       startTime: new Date().getTime(),       __expires__: expires     }     this.storage.setItem(key, JSON.stringify(storeValue))   }   /**    * @description 获取方法    * @param {String} key 键名    * @returns {any} 值    */   get(key: string) {     try {       const storeItem = this.storage.getItem(key) || "{}"       const storeValue = JSON.parse(storeItem)       const time = new Date().getTime()       // 如果是永久,则直接返回       if (storeValue?.__expires__ === 0) return storeValue       // 判断当前时间是否过期       if (storeValue?.startTime && (time - storeValue?.startTime >= storeValue?.__expires__)) {         this.remove(key);         return null;       }       return storeValue.value     } catch (error) {       return null     }   }   /**    * @description 删除方法    * @param {String} key 删除键名    */   remove(key: string) {     key && this.storage.removeItem(key);   }   /**    * @description 清除所有本地存储    */   clear() {     this.storage.clear();   } }
  下面是本地测试:const store = new NStorage()  store.set("name", "小红", { expires: 10 })  let count = 0 const time = setInterval(() => {   const name = store.get("name")   console.log(name)   count += 1    if (count > 10) {     clearInterval(time)   } }, 1000)
  在控制台可以看见打印的 小红 ,3秒后localStorage 里面的值就会被删除。功能我们是实现啦,是不是就可以皆大欢喜了?有没有bug?有没有可以优化的问题了?那当然是有的了:
  1. 设置的过期时间,表示的是秒?分?小时?
  2. 如果多次设置同一个值,那么依据现在逻辑,每次都会重新计算时间,但是我可能只是更新值,时间不需要重新计算了?优化
  定义出选项类型// 定义支持时间类型,依次:年、月、日、时、分、秒 type TUnitType = "Y" | "M" | "D" | "h" | "m" | "s" // 定义可选参类型 interface IExtraOptions {   expires?: number;   unit?: TUnitType,   reset?: boolean }  // 设置默认初始值 const EXTRA_OPTIONS: IExtraOptions = {   expires: 0, // 默认永久   unit: "s", // 默认秒   reset: false // 是否重置时间 } // 根据单位和传入时间,计算出毫秒级时间 function calcTime(time: number, unit: TUnitType = "s") {   let newTime = 0   switch (unit) {     case "Y":       newTime = time * 365 * 24 * 60 * 60 * 1000       break;     case "M":       // 注意⚠️:月份这里偷懒,直接使用每月30天计算       newTime = time * 30 * 24 * 60 * 60 * 1000       break;     case "D":       newTime = time * 24 * 60 * 60 * 1000       break;     case "h":       newTime = time * 60 * 60 * 1000       break;     case "m":       newTime = time * 60 * 1000       break;     case "s":       newTime = time * 1000       break;     default:       newTime = time       break;   }   return newTime }   **修改 set、get 方法**    /**    * @description 存储方法    * @param {String} key 键名    * @param {any} value 值    * @param {number} [options] 可选    * @param {Number} [options.expires] 默认0,永久    * @param {String} [options.unit] 默认"s",秒    * @param {Boolean} [options.reset] 默认false,不重置    */   set(key: string, value: any, options?: IExtraOptions) {   const isExist = this.hasKey(key)   const extra = Object.assign(EXTRA_OPTIONS, options)   if (isExist) {     // 如果存在,判断是否是需要重新设置值     const sValue = this.get(key, true)     sValue.value = value     sValue.__expires__ = calcTime(extra.expires || sValue.__expires__, extra.unit || sValue.__unit__)     if (extra.reset) {       // 存在且重新设置时间       sValue.startTime = new Date().getTime()       this._set(key, sValue)     } else {       // 如果已经存在,且不重新计算时间,则直接修改值后存储       this._set(key, sValue)     }   } else {     const storeValue = {       value,       startTime: new Date().getTime(),       __expires__: calcTime(extra.expires as number, extra.unit),       __unit__: extra.unit     };     this._set(key, storeValue)   } }   /**    * @description set内部方法    * @param {String} key 键名    * @param {any} value 值    */   private _set(key: string, value: any) {     this.storage.setItem(key, JSON.stringify(value));   }   /**    * @description 获取方法    * @param {String} key 键名    * @param {Boolean} [isMerge] 可选,是否获取处理后的对象    * @returns {any} 值    */   get(key: string, isMerge: boolean = false) {     try {       // 不存在直接返回 null       if (!key) return null       const storeItem = this.storage.getItem(key) || "{}"       const storeValue = JSON.parse(storeItem)       const time = new Date().getTime()       // 如果是永久,则直接返回       if (storeValue?.__expires__ === 0) return isMerge ? storeValue : storeValue.value;       // 判断当前时间是否过期,过期则删除当前存储值       if (storeValue?.startTime && (time - storeValue?.startTime >= storeValue?.__expires__)) {         this.remove(key);         return null;       }       return isMerge ? storeValue : storeValue.value;     } catch (error) {       return null     }   }   /**    * @description 是否存在    * @param {String} key 键    * @returns {Boolean} true|false    */   hasKey(key: string) {     if (!key) return false     const value = this.get(key)     return value ? true : false   }优化后使用介绍const store = new NStorage() // 普通设置,不过期 store.set("name", "小红") // 设置过期时间5秒 store.set("name", "小红", { expires: 5 }) // 设置过期时间5分钟,其他更换单位即可 store.set("name", "小红", { expires: 5, unit: "m" }) // 重新计算有效时长(就相当于在设置的时刻起,再往后延长之前的设置时间) store.set("name", "小红", { reset: true })  // 获取值 store.get("name")  // 删除值 store.remove("name")  // 删除所有值 store.clear()  // 当前存储值中是否存在 store.hasKey("name")完整版代码// 定义支持时间类型,依次:年、月、日、时、分、秒 type TUnitType = "Y" | "M" | "D" | "h" | "m" | "s" // 定义可选参类型 interface IExtraOptions {   expires?: number;   unit?: TUnitType,   reset?: boolean }  // 设置默认初始值 const EXTRA_OPTIONS: IExtraOptions = {   expires: 0, // 默认永久   unit: "s", // 默认秒   reset: false // 是否重置时间 } // 根据单位和传入时间,计算出毫秒级时间 function calcTime(time: number, unit: TUnitType = "s") {   let newTime = 0   switch (unit) {     case "Y":       newTime = time * 365 * 24 * 60 * 60 * 1000       break;     case "M":       // 月份这里偷懒,直接使用每月30天计算       newTime = time * 30 * 24 * 60 * 60 * 1000       break;     case "D":       newTime = time * 24 * 60 * 60 * 1000       break;     case "h":       newTime = time * 60 * 60 * 1000       break;     case "m":       newTime = time * 60 * 1000       break;     case "s":       newTime = time * 1000       break;     default:       newTime = time       break;   }   return newTime }  class NStorage {   storage: Storage;   constructor(name?: string) {     this.storage = window[name as keyof typeof window] || window.localStorage   }   /**    * @description 存储方法    * @param {String} key 键名    * @param {any} value 值    * @param {number} [options] 可选    * @param {Number} [options.expires] 默认0,永久    * @param {String} [options.unit] 默认"s",秒    * @param {Boolean} [options.reset] 默认false,不重置    */   set(key: string, value: any, options?: IExtraOptions) {     const isExist = this.hasKey(key)     const extra = Object.assign(EXTRA_OPTIONS, options)     if (isExist) {       // 如果存在,判断是否是需要重新设置值       const sValue = this.get(key, true)       sValue.value = value       sValue.__expires__ = calcTime(extra.expires || sValue.__expires__, extra.unit || sValue.__unit__)       if (extra.reset) {         // 存在且重新设置时间         sValue.startTime = new Date().getTime()         this._set(key, sValue)       } else {         // 如果已经存在,且不重新计算时间,则直接修改值后存储         this._set(key, sValue)       }     } else {       const storeValue = {         value,         startTime: new Date().getTime(),         __expires__: calcTime(extra.expires as number, extra.unit),         __unit__: extra.unit       };       this._set(key, storeValue)     }   }   /**    * @description set内部方法    * @param {String} key 键名    * @param {any} value 值    */   private _set(key: string, value: any) {     this.storage.setItem(key, JSON.stringify(value));   }   /**    * @description 获取方法    * @param {String} key 键名    * @param {Boolean} [isMerge] 可选,是否获取处理后的对象    * @returns {any} 值    */   get(key: string, isMerge: boolean = false) {     try {       // 不存在直接返回 null       if (!key) return null       const storeItem = this.storage.getItem(key) || "{}"       const storeValue = JSON.parse(storeItem)       const time = new Date().getTime()       // 如果是永久,则直接返回       if (storeValue?.__expires__ === 0) return isMerge ? storeValue : storeValue.value;       // 判断当前时间是否过期,过期则删除当前存储值       if (storeValue?.startTime && (time - storeValue?.startTime >= storeValue?.__expires__)) {         this.remove(key);         return null;       }       return isMerge ? storeValue : storeValue.value;     } catch (error) {       return null     }   }   /**    * @description 删除方法    * @param {String} key 删除键名    */   remove(key: string) {     key && this.storage.removeItem(key);   }   /**    * @description 清除所有本地存储    */   clear() {     this.storage.clear();   }   /**    * @description 是否存在    * @param {String} key 键    * @returns {Boolean} true|false    */   hasKey(key: string) {     if (!key) return false     const value = this.get(key)     return value ? true : false   } }最后
  里面的逻辑也可根据需求自己添加修改,代码测试我也可能存在未测到的地方,如果有问题欢迎各位大大指出!

清朝人的真实发型是怎样的?比一黑一白的阴阳头,还一言难尽古代汉族男子二十及冠,父母将男子的头发用发冠高高束起,代表成人仪式。之后虽然这个仪式不再这么隆重,但是在人们的内心也一直尊重着。毕竟是老祖宗流传下来的,人们都一直信仰着华夏的传统文细说雍正皇帝在康熙十七年十月三十日,在一个大雪纷飞的一天,雍正皇帝出生了,他的生母是宫女小凤,按照序齿的几位皇子,雍正应该排名第四,宫廷称他为四阿哥,钮枯禄皇后非常喜欢这个孩子,她很想收养这个42岁薛涛爱上31岁元稹,缠绵1年后被抛弃,薛涛不困于爱情天才作家张爱玲说这世上没有一样感情不是千疮百孔的。想必只有受过极深感情伤害的人,才会有如此深切的体会。然而,薛涛例外。公元809年,42岁的蜀中才女薛涛,结识了她生命里一个非常重要安奈儿收到深交所关注函要求说明其产品相关信息是否真实12月1日晚间,安奈儿披露深交所下发的收关注函。深交所要求安奈儿说明,安奈儿水木拟推广应用的电子束接枝改性面料实际功效相关检测结论等信息是否真实准确,电子束接枝技术与其他也具有抗病后宫佳丽三千,来例假后是怎样应付皇帝的?她们有四种方法这个世界上谁的老婆最多?当然是我们中国历代的皇帝了,皇帝后宫三宫六院,更是有三千佳丽,可以说是天天做新郎也可能到白日飞升都玩不完,毕竟每年也会有新的佳丽进宫。但是她们大多人可能一辈雍正皇帝传(一)爱新觉罗。胤禛是康熙皇帝的第四个儿子,出生于康熙十七年,他的生母只是一个宫女,身份卑微,因为封建社会宫女的地位卑微,每天资格扶养皇子,胤禛还没出生就已经打算指派给别的妃子,他的监护降臣杀主斩草除根的吴三桂300多年前,有人用文字记载的吴三桂是一个充满激情才华能量的男人。但之后,用来形容吴三桂的文字就远远不止这些了,取而代之的是另外儿几个更能让世人铭记于心的标签降臣汉奸忘恩负义卖主求戈培尔洗脑鼻祖宣传天才纳粹恶棍的著名语录转发自小c漫谈戈培尔(德语PaulJosephGoebbels,18971945),德国人,文学博士,第二次世界大战期间担任德国纳粹党中央宣传部部长。戈培尔,被认为是创造希特勒的人军营版我和我的父辈两位新兵,四代皆从军历尽战火硝烟的年代,再到新时代的中国,在信息通信部队海南某部新兵营里,有这样两位新兵,四代皆从军。这红色的血脉,这不变的忠诚,如今由胡韫涵和刘星际接续传承。今天,小编带你们听听他们你知道新乡石榴园大街的由来吗?新乡哪条路石榴树最多?在新乡一提石榴园大街,大家都知道它是位于劳动路和胜利路之间沿着卫河走向的一条街,明明是一条小街巷,但是为什么叫石榴园大街呢?我们先说一下石榴园的来历,在唐朝的时候,居住在新乡县的大中国历史上第一个使用间谍的国君有多牛?中国及世界史上首个第一个使用间谍的国君有多牛,一边是巴掌大的流亡之地和500名奴隶,一边是国土辽阔,兵强马壮。真正意义上的开局一条狗,装备全靠打。他是立志图强,忍辱负重的报复者。他
003前传,中国在瓦良格号航母上学到和没学的航母建造知识前言福建号航母装上曾经被称为研制难度比上天难的电磁弹射系统,环顾全球,只有美国海军的福特级航母才用电磁弹射系统,可是福特级航母的电磁弹射系统问题重重,导致开支增长和进度推迟,至今还明明老天爷赏饭吃,却偏偏作死动脸,这6位女星,既可惜又活该爱美之心,人皆有之。尤其在颜值就是饭碗的娱乐圈,明星为了美而去整容早就是行业内公开的秘密,连倪萍姐姐都在节目里直言现在哪个明星没整过容。同时她还表示,微调可以,但是在脸上大动干戈弄巷子最后发生了什么?发声录音非被打女孩,请官方证实女孩们平安听了一段唐山烧烤店最后白衣女子逃进巷子里后,那撕心裂肺的哭喊声,以及被打其中一女孩的发声。我不知这个到底真假!首先不管真假,最后巷子里肯定发生了更为惨烈的画面。那么目前四名女孩情况疑似违反开源协议,一加被网友骂惨了时间倒回前几年,如果要问安卓阵营有哪个品牌,能让人Duang地眼前一亮?不像哔哥纠结老半天,小雷脱口而出就是一加。原因很简单,那时的一加确实对得起推出时标榜的口号NeverSett判了!茅台杜光义,无期中国基金报记者南深又一名领导干部利用茅台酒谋取私利被判刑。黔东南州中级人民法院官微消息,2022年6月17日上午,该院一审公开宣判贵州茅台股份有限公司原副总经理中国贵州茅台酒厂(集6月17日下午,纪委又通报6名干部涉嫌违纪违法被查处,看看是谁?6月17日上午,中纪委省纪委网站通报6名干部涉嫌严重违纪违法被查处。下午又通报了6名厅局级干部被查处,至此,17日已通报12名干部被查处。其中,8名干部受到党纪政务处分,4名干部正英媒关注香港新课本明确香港从来不是英国殖民地据英国泰晤士报网站6月15日报道,香港对教科书中的一项内容进行了全面修改,新版教材明确表示,香港从来不是英国的殖民地。报道称,新版公民与社会发展科(公民科)教材说,中国历届政府都不唐山主犯身后恶行不断,牵出一大串葡萄,知情人或有大动作夏天到来了,你是否也想在傍晚来临,约上三五好友,一起去烧烤摊上吃吃烤串喝喝啤酒,感觉一天中最美妙的时刻就是此时了。然而,越是在我们放松的时刻,意外就越是容易降临。唐山烧烤店打人的事美联储加息落地以后中美在经济战场上的势博弈,全面开启?这是熊猫贝贝的第1132篇原创文章身处时代转折,见证局势风云变化的个体,是无法感知到波澜壮阔的局势之变的,这就是时代的局限性,只有在未来,经过梳理和复盘之后,才会幡然醒悟,原来自己习近平总书记的回信激励我为深化非中友谊而努力尼雷尔领导力学院南部非洲六姊妹党中青年干部研讨班全体学员日前收到中共中央总书记习近平的回信。这封回信令研讨班全体学员非常喜悦深受鼓舞。他们纷纷表示,将为国家发展民族振兴和非中合作贡中央决定宋志勇任中国民用航空局党组书记6月17日下午,中央组织部有关负责同志出席中国民用航空局领导干部会议,宣布中央决定宋志勇同志任中国民用航空局党组书记,免去冯正霖同志的中国民用航空局党组书记职务。宋志勇资料图此前,