实现一个管理本地缓存过期的函数

封装 localStorage,实现带过期时间的本地缓存管理功能

问题

原生的 localStorage 只能永久存储数据,不支持设置过期时间。在实际开发中,我们经常需要为缓存数据设置有效期,过期后自动失效。本题要求实现一个带过期时间管理的本地缓存工具函数。

解答

class CacheStorage {
  constructor(storage = localStorage) {
    this.storage = storage;
  }

  /**
   * 设置缓存
   * @param {string} key - 缓存键名
   * @param {any} value - 缓存值
   * @param {number} expire - 过期时间(毫秒),不传则永久有效
   */
  set(key, value, expire) {
    const data = {
      value,
      expire: expire ? Date.now() + expire : null
    };
    
    try {
      this.storage.setItem(key, JSON.stringify(data));
    } catch (error) {
      console.error('缓存设置失败:', error);
    }
  }

  /**
   * 获取缓存
   * @param {string} key - 缓存键名
   * @returns {any} 缓存值,过期或不存在返回 null
   */
  get(key) {
    try {
      const item = this.storage.getItem(key);
      
      if (!item) {
        return null;
      }

      const data = JSON.parse(item);
      
      // 检查是否过期
      if (data.expire && Date.now() > data.expire) {
        this.remove(key);
        return null;
      }

      return data.value;
    } catch (error) {
      console.error('缓存读取失败:', error);
      return null;
    }
  }

  /**
   * 删除缓存
   * @param {string} key - 缓存键名
   */
  remove(key) {
    this.storage.removeItem(key);
  }

  /**
   * 清空所有缓存
   */
  clear() {
    this.storage.clear();
  }

  /**
   * 检查缓存是否存在且未过期
   * @param {string} key - 缓存键名
   * @returns {boolean}
   */
  has(key) {
    return this.get(key) !== null;
  }

  /**
   * 清理所有过期缓存
   */
  clearExpired() {
    const keys = Object.keys(this.storage);
    
    keys.forEach(key => {
      try {
        const item = this.storage.getItem(key);
        if (item) {
          const data = JSON.parse(item);
          if (data.expire && Date.now() > data.expire) {
            this.remove(key);
          }
        }
      } catch (error) {
        // 忽略解析错误的项
      }
    });
  }
}

// 创建默认实例
const cache = new CacheStorage();

// 导出函数式 API
export const setCache = (key, value, expire) => cache.set(key, value, expire);
export const getCache = (key) => cache.get(key);
export const removeCache = (key) => cache.remove(key);
export const clearCache = () => cache.clear();
export const hasCache = (key) => cache.has(key);
export const clearExpiredCache = () => cache.clearExpired();

export default cache;

使用示例

// 示例 1: 基本使用
cache.set('username', 'zhangsan', 5000); // 5秒后过期
console.log(cache.get('username')); // 'zhangsan'

setTimeout(() => {
  console.log(cache.get('username')); // null (已过期)
}, 6000);

// 示例 2: 存储对象数据
const userInfo = {
  id: 1,
  name: '张三',
  age: 25
};
cache.set('userInfo', userInfo, 60 * 60 * 1000); // 1小时后过期

// 示例 3: 永久缓存(不设置过期时间)
cache.set('theme', 'dark');
console.log(cache.get('theme')); // 'dark'

// 示例 4: 检查缓存是否存在
if (cache.has('token')) {
  console.log('用户已登录');
} else {
  console.log('请先登录');
}

// 示例 5: 清理过期缓存
cache.set('temp1', 'data1', 1000);
cache.set('temp2', 'data2', 2000);
cache.set('permanent', 'data3'); // 永久

setTimeout(() => {
  cache.clearExpired(); // 清理过期的 temp1 和 temp2
  console.log(cache.get('permanent')); // 'data3' (仍然存在)
}, 3000);

// 示例 6: 使用函数式 API
import { setCache, getCache, removeCache } from './cache';

setCache('token', 'abc123', 24 * 60 * 60 * 1000); // 24小时
const token = getCache('token');
removeCache('token');

关键点

  • 数据结构设计:将值和过期时间封装成对象存储,格式为 { value, expire }
  • 过期判断:读取时检查 Date.now() > expire,过期则自动删除并返回 null
  • 异常处理:使用 try-catch 捕获 JSON 解析和存储异常,避免程序崩溃
  • 灵活性:支持设置过期时间或永久存储(expire 为 null)
  • 类封装:使用 class 封装,支持传入不同的 storage(localStorage/sessionStorage)
  • API 完整性:提供 set、get、remove、clear、has 等完整的缓存操作方法
  • 主动清理:提供 clearExpired 方法批量清理过期缓存,优化存储空间
  • 类型支持:自动序列化和反序列化,支持存储对象、数组等复杂类型