·vincent
封装LocalStorage并支持过期时间
在浏览器开发中,我们经常需要在客户端存储数据,以便在不同页面或会话之间进行持久化。本文介绍了常用的客户端存储机制cookie与localStorage,并探讨了它们在一些方面存在的限制和差异。此外,还提供了一种解决方案,通过对localStorage进行封装,实现了为数据设置有效期的功能。
Javascriptweb安全缓存
在浏览器开发中,我们经常需要在客户端存储数据,以便在不同页面或会话之间进行持久化。cookie
和localStorage
是常用的客户端存储机制。然而,它们在一些方面存在一些限制和差异。
cookie
cookie
是存储在客户端的小型文本文件,每当用户与服务器进行通信时都会在请求和响应中传递。cookie
可以设置过期时间,可以是会话级别(浏览器关闭后过期)或持久性(在指定时间之后过期)。cookie
可以在不同页面之间共享,并且可以用于实现用户身份验证、记住用户偏好等功能。- 但是,每个请求都会将
cookie
发送到服务器,这可能会增加网络流量,并且对于每个请求都需要服务器进行处理。
localStorage
localStorage
是HTML5中提供的一个客户端存储机制,用于存储较大量级的数据。localStorage
使用key-value
的方式存储数据,并且数据存储在浏览器的本地。localStorage
没有过期时间的设置机制,存储的数据会一直存在于浏览器中,直到被手动删除。localStorage
的数据可以在不同页面之间共享,并且在浏览器关闭后仍然保留。localStorage
提供了简单的API来存储、获取和删除数据。
思考
在使用cookie
时,我们可以设置有效期限,但localStorage
本身并不具备该机制,它只能手动删除数据,否则数据将一直保存在浏览器中。那么,我们能否像cookie
一样为localStorage
设置有效期限呢?为了解决这个问题,我们可以对localStorage
进行二次封装,以实现这一功能。
实现思路
在存储数据时,我们可以设置一个过期时间,并对存储的数据进行格式化,以便进行统一校验。在读取数据时,我们可以获取当前时间,并判断数据是否过期。如果数据过期了,我们可以将其删除。
代码实现
目录结构
enum.ts
:定义枚举
typescript
1// 字典 Dictionaries
2// expire过期时间key
3// permanent永久不过期
4export enum Dictionaries {
5 expire = '__expire__',
6 permanent = 'permanent'
7}
type.ts
:定义类型
typescript
1import { Dictionaries } from "../enum";
2
3export type Key = string; // key类型
4export type Expire = Dictionaries.permanent | number; // 有效期类型
5
6export interface Data<T> { // 格式化data类型
7 value: T;
8 [Dictionaries.expire]: Expire;
9}
10
11export interface Result<T> { // 返回值类型
12 message: string;
13 value: T | null;
14}
15
16export interface StorageCls { // class方法约束
17 set: <T>(key: Key, value: T, expire: Expire) => void;
18 get: <T>(key: Key) => Result<T | null>;
19 remove: (key: Key) => void;
20 clear: () => void;
21}
index.ts
:主要逻辑实现
typescript
1import { StorageCls, Key, Expire, Data, Result } from "./type";
2import { Dictionaries } from "./enum";
3
4export class Storage implements StorageCls {
5 // 存储接受 key value 和过期时间 默认永久
6 public set<T = any>(key: Key, value: T, expire: Expire = Dictionaries.permanent) {
7 // 格式化数据
8 const data: Data<T> = {
9 value,
10 [Dictionaries.expire]: expire
11 };
12 // 存入localStorage
13 localStorage.setItem(key, JSON.stringify(data));
14 }
15
16 public get<T = any>(key: Key): Result<T | null> {
17 const value = localStorage.getItem(key);
18
19 // 检查读取的数据是否有效
20 if (value) {
21 const obj: Data<T> = JSON.parse(value);
22 const now = new Date().getTime();
23
24 // 检查是否过期,如果过期则删除并返回提示信息
25 if (typeof obj[Dictionaries.expire] === 'number' && obj[Dictionaries.expire] < now) {
26 this.remove(key);
27 return {
28 message: `您的${key}已过期`,
29 value: null
30 };
31 } else {
32 // 数据有效,返回成功读取的值
33 return {
34 message: "成功读
35
36取",
37 value: obj.value
38 };
39 }
40 } else {
41 // 无效的key值
42 console.warn('无效的key值');
43 return {
44 message: `key值无效`,
45 value: null
46 };
47 }
48 }
49
50 // 删除某一项
51 public remove(key: Key) {
52 localStorage.removeItem(key);
53 }
54
55 // 清空所有值
56 public clear() {
57 localStorage.clear();
58 }
59}
rollup.js
:简易打包配置(依赖:rollup
、rollup-plugin-typescript2
、typescript
)
旧版写法:
typescript
1import ts from 'rollup-plugin-typescript2';
2import path from 'path';
3
4export default {
5 input: './src/index.ts',
6 output: {
7 file: path.resolve(__dirname, './dist/index.js')
8 },
9 plugins: [
10 ts()
11 ]
12};
新版写法:
typescript
1import ts from 'rollup-plugin-typescript2';
2import path from 'path';
3import { fileURLToPath } from 'url';
4
5const metaUrl = fileURLToPath(import.meta.url);
6const dirName = path.dirname(metaUrl);
7
8export default {
9 input: './src/index.ts',
10 output: {
11 file: path.resolve(dirName, './dist/index.js')
12 },
13 plugins: [
14 ts()
15 ]
16};
代码测试
html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>Document</title>
8</head>
9<body>
10 <script type="module">
11 import { Storage } from './dist/index.js';
12
13 const sl = new Storage();
14
15 // 五秒后过期
16 sl.set('a', 123, new Date().getTime() + 5000);
17
18 setInterval(() => {
19 const a = sl.get('a');
20 console.log(a);
21 }, 500);
22 </script>
23</body>
24</html>
通过设置定时器,在五秒后观察值是否过期并删除,测试成功。