核心是用闭包封装双Map结构:主Map存键值对,辅助Map存毫秒级expiresAt时间戳,通过工厂函数暴露set/get/clear方法,支持惰性检查与定时扫描双清理,并可选TTL或滑动TTL模式。

用 Map 模拟 TTL 缓存,核心是让每个缓存项自带“死亡倒计时”,在长连接场景下避免客户端持续收到陈旧数据。关键不在存得快,而在判得准、清得稳。
用闭包封装过期状态,隔离时间逻辑
直接往 Map 里塞 value 不行——缺时间戳,没法判断是否过期。正确做法是:用工厂函数创建缓存实例,内部用两个 Map 协同工作:
- 主 Map 存键值对(key → value)
- 辅助 Map 存过期时间(key → expiresAt(毫秒时间戳))
- 所有 set/get/clear 操作都走闭包内方法,外部无法绕过逻辑直接操作底层 Map
这样既保证 key 的稳定性(推荐用 string/number),又防止时间状态被意外篡改或泄漏。
支持惰性 + 主动双清理,防冷数据堆积
长连接应用往往存在“连接一直在线、但某类数据长期不访问”的情况。只靠 get 时检查过期(惰性)会导致内存缓慢上涨。必须叠加主动扫描:
- 每次 set 时,检查当前 key 是否已有定时器,有则 clearTimeout 清除旧的
- 为每个 key 单独设 setTimeout 删除(适合低频写、高时效场景)
- 更推荐:启动一个全局 setInterval(如每 30 秒),遍历辅助 Map,批量删除所有 expiresAt ≤ Date.now() 的 key,并同步清理主 Map 中对应项
注意 clearInterval 的清理时机,尤其在服务重启或模块卸载时显式调用,避免定时器残留。
适配长连接的数据新鲜度控制策略
单纯 TTL 不够智能。长连接中,有些数据应“越活跃越长寿”,比如用户会话 token;有些则“一过就废”,比如临时验证码。可按需组合:
- TTL 模式:适用于强时效数据(如短信验证码),创建即锁定过期时间,不因访问而延长
- Sliding TTL 模式:每次 get/set 都刷新 expiresAt,适合会话、用户偏好等需保活的数据
- 两者可在同一缓存实例中按 key 分类启用,通过 set(key, value, { ttl: 60000, sliding: true }) 控制
这样服务端能主动控制推送节奏,前端长连接收到变更通知后,也能及时触发本地缓存刷新。
轻量但不失健壮:规避常见陷阱
Map + TTL 看似简单,实操中几个点容易翻车:
- 避免用对象或数组作 key —— 引用不同导致重复存入、无法命中、过期项漏删
- 大对象缓存(如用户完整 profile)需配合 clear 或组件 unmount 显式释放,防止 V8 内存滞留
- 多线程/多实例环境(如 Node.js cluster)下,单机 Map 无法共享,此时应退回到 Redis 等分布式方案
- 监控辅助 Map.size 和平均存活时长,若长期不降,说明扫描未生效或时间判断逻辑有误
不复杂但容易忽略。

















