当前位置: 首页 > news >正文

10.5 小项目:如何用 JavaScript 实现一个高效的时间+Token过期容器?

在开发中,我们经常会遇到需要临时存储数据并定时过期的场景,比如:

  • 用户登录后的临时 Token 缓存
  • 短信验证码的有效期管理
  • 接口限流中的请求记录
  • 临时会话状态存储

这类需求通常具备以下特点:

  • 存储 token 值和其生成时间
  • 时间可能重复(多个 token 同时生成)
  • 需要 快速判断某个 token 是否存在
  • 数据在 20 分钟后自动过期并清除

一、需求拆解

我们明确一下核心需求:

需求描述
✅ 存储结构每条记录包含:token(字符串) + timestamp(时间戳)
✅ 时间可重复允许多个 token 在同一时间生成
✅ 快速查询能在 O(1) 时间内判断某个 token 是否存在
✅ 自动过期所有数据在插入后 20 分钟自动失效
✅ 高效清理定期清理过期数据,不影响主线程性能

常见实现方式对比

方案 1:仅用数组存储(不推荐)

const tokens = [];
tokens.push({ token: 'abc', timestamp: Date.now() });
  • ❌ 查询 token:需遍历数组,O(n)
  • ❌ 清理过期:每次都要全量扫描
  • ❌ 性能差,不适合高频查询

方案 2:Map + setTimeout(精确但开销大)

为每个 token 设置一个 setTimeout,20 分钟后删除。

  • ✅ 删除精确到毫秒
  • ❌ 内存开销大:每个 token 一个定时器
  • ❌ 大量 token 时可能导致事件循环阻塞

✅ 方案 3:Set + 时间队列 + 定时扫描(推荐)

  • 使用 Set 快速判断 token 是否存在(O(1))
  • 使用数组(队列)按插入顺序存储 {token, timestamp}
  • 启动一个定时器,定期扫描并清理过期数据

⭐ 这是本文推荐的平衡性能与资源消耗的最佳实践

✅ 核心设计思路

  1. 快速查找 token:使用 Set 或 Map 来存储 token,实现 O(1) 时间复杂度的查找。
  2. 处理重复时间 & 存储时间:将时间戳和 token 一起存储,并通过一个列表或队列维护插入顺序,以便按时间清理。
  3. 定时清除过期数据:使用一个定时器(setInterval)每隔几分钟扫描一次,清除超过 20 分钟的数据。

✅ 推荐实现:使用 Set + 时间队列

class TokenExpiryContainer {constructor() {this.tokenSet = new Set();           // 用于 O(1) 快速判断 token 是否存在this.tokenQueue = [];                // 存储 { token, timestamp },按插入时间排序this.EXPIRY_MS = 20 * 60 * 1000;     // 20分钟过期this.CLEAN_INTERVAL = 10 * 60 * 1000; // 每10分钟检查一次过期数据(可调)// 启动定时清理this.startCleaner();}/*** 添加 token 和时间* @param {string} token* @param {number} timestamp - 时间戳(毫秒),默认为当前时间*/add(token, timestamp = Date.now()) {// 如果 token 已存在,无需重复添加if (this.has(token)) return;this.tokenSet.add(token);this.tokenQueue.push({ token, timestamp });}/*** 判断 token 是否存在(未过期)* @param {string} token* @returns {boolean}*/has(token) {return this.tokenSet.has(token);}/*** 获取所有未过期的 token* @returns {string[]}*/getAllTokens() {const now = Date.now();return this.tokenQueue.filter(item => now - item.timestamp < this.EXPIRY_MS).map(item => item.token);}/*** 启动定时清理任务*/startCleaner() {setInterval(() => {this.cleanupExpired();}, this.CLEAN_INTERVAL);}/*** 清理过期数据*/cleanupExpired() {const now = Date.now();const expiryTime = now - this.EXPIRY_MS;let removedCount = 0;// 由于 tokenQueue 是按时间顺序插入的,我们可以从头部开始清理while (this.tokenQueue.length > 0) {const firstItem = this.tokenQueue[0];if (firstItem.timestamp <= expiryTime) {// 移除过期 tokenthis.tokenQueue.shift();this.tokenSet.delete(firstItem.token);removedCount++;} else {// 队列是有序的,第一个没过期,后面的都不会过期,提前退出break;}}if (removedCount > 0) {console.log(`清理了 ${removedCount} 个过期 token`);}}
}// === 使用示例 ===
const container = new TokenExpiryContainer();// 添加一些 token(时间可能重复)
container.add('token1', 1700000000000); // 模拟时间
container.add('token2', 1700000000000); // 相同时间
container.add('token3', Date.now());     // 当前时间console.log(container.has('token1')); // true
console.log(container.has('token999')); // false// 20分钟后,token1 和 token2 会被自动清理

✅ 为什么这个设计高效?

需求实现方式时间复杂度
快速判断 token 是否存在使用 Set 存储 tokenO(1)
存储时间 + tokentokenQueue 数组存储 {token, timestamp}O(1) 插入
清除过期数据定时扫描 + 队列有序性(提前退出)O(k),k 是过期数量,通常很小

✅ 总结

  • ✅ 时间可重复:使用独立的 timestamp 字段,不作为键。
  • ✅ 快速判断 tokenSet 提供 O(1) 查找。
  • ✅ 定时清除setInterval + 有序队列,高效清理。

性能优化建议

优化点说明
 扫描频率CLEAN_INTERVAL 不宜太短(如 1 秒),避免频繁扫描;也不宜太长(如 30 分钟),导致过期数据滞留。5到10 分钟较合理
 内存优化如果 token 数量极大,可考虑使用  Redis。
 精确删除若需精确删除,可用 Map 存储 token -> timeoutId,但需权衡内存。
 持久化Node.js 重启后数据丢失?可将数据持久化到文件或数据库。
 批量清理生产环境可结合 Redis 的 ZSET + EXPIRE 实现更强大的过期管理。

适用场景

  • 🔐 临时 Token 缓存:OAuth2 临时凭证、JWT 刷新 Token
  • 📱 验证码管理:短信、邮箱验证码的时效控制
  • 🛑 接口限流:记录用户请求时间,防止刷接口
  • 🧩 会话管理:轻量级 session 存储,无需引入 Redis
  • 🔄 任务去重:防止重复提交、重复处理

本文实现了一个高效、低延迟的“时间+Token”过期容器,具备以下优势:

  • ✅ O(1) 查询:使用 Set 实现快速存在性判断
  • ✅ 支持重复时间:独立存储时间戳,互不影响
  • ✅ 自动清理:定时扫描 + 有序队列,高效清除过期数据
  • ✅ 轻量无依赖:纯 JavaScript 实现,适合嵌入任何项目

💡 最佳实践建议
对于小规模应用,本文方案完全够用;
对于高并发、大规模场景,建议使用 Redis 配合 EXPIREZSET 实现更可靠的过期机制。


http://www.dtcms.com/a/533296.html

相关文章:

  • 网站备案帐号找回密码免费友链平台
  • Every other Cycle Command Input(隔循环命令输入)
  • 更换docker默认镜像仓库地址方法
  • 福建省交通建设质量安全监督局网站软文写作技巧
  • 装饰公司营销型网站设计网站图片等比缩小
  • 高端网站制作价格大型大型网站建设方案ppt模板
  • 【底层机制】Linux内核4.10版本的完整存储栈架构讲解--用户空间到物理设备完整IO路径
  • nodejs 使用speaker + ffmpeg 实现静默播放MP3
  • 【大模型应用开发 LangChain模型输出属性速查表】
  • 南京 电子商务网站WordPress实现微信一键登录
  • 豫icp郑州网站建设做视频网站要什么
  • 商丘手机网站制作西安怡佳然网络科技有限公司
  • 开发制作一个网站北京做网站的公司商集客电话
  • 第七章:理解篇 - 对接云端语音识别,让助手“听懂”人话
  • 长春做网站多少钱全屏背景网站
  • 企业做淘宝网站需要多少钱王烨森
  • 课后作业-2025-10-26
  • 外管局网站先支后收怎么做报告企业网站开发需求
  • 网站域名所有权证书网站后台 全局配置
  • python之pydantic使用小结
  • 有什么好的网站建设的书厚街外贸网站建设
  • 从Google Chrome商店下载CRX文件
  • 做微信公众平台的网站欧美设计网站
  • 网站建设介绍ppt模板下载wordpress谷歌字体库
  • 高职护理专业就业指南:医院就业路径与职业发展
  • STM32F103C8T6--ADC
  • 怎么建设公益网站建公司网站的公司
  • shell脚本练习题1.0
  • 网站开发费的会计处理济南市工程建设技术监督局网站
  • 增城网站公司电话做网站在厦门排前5名