JS中TimeLimitedCache的setTimeout使用问题排查请求
TimeLimitedCache缓存类的问题分析
最近练习JavaScript数据结构与算法,实现了一个支持键值自动过期的TimeLimitedCache缓存类,但实际运行输出与预期不符。以下是实现代码及测试逻辑:
function TimeLimitedCache(){ this.cache = {}; this.set = function (key, value, duration) { let timer; let result = false; if(key in this.cache){ clearTimeout(timer); result = true; } this.cache[key] = value; timer = setTimeout(()=> delete this.cache[key],duration); return result; } this.get = function(key){ return this.cache[key] ? this.cache[key] : -1; } this.count = function(){ return Object.keys(this.cache).length; } } const start = new Date().getSeconds(); const tesr = new TimeLimitedCache(); setTimeout(()=>console.log(tesr.set(1,42,50)),start) setTimeout(()=>console.log(tesr.set(1,50,100)),start+40) setTimeout(()=>console.log(tesr.get(1)),start+50) setTimeout(()=>console.log(tesr.get(1)),start+120) setTimeout(()=>console.log(tesr.get(1)),start+200) setTimeout(()=>console.log(tesr.count(1)),start+250)
问题原因分析
- 定时器清除逻辑失效:
set方法中的timer是局部变量,每次调用set都会创建新的变量实例。当更新同一个key时,clearTimeout(timer)清除的是刚声明的空timer(值为undefined),完全无法触达之前为该key设置的定时器。旧定时器仍会在到期后删除缓存,导致后续读取结果不符合预期。 - 缓存结构设计缺陷:当前
cache对象仅存储键值对,未保存对应key的定时器ID,无法在更新key时定位并清除旧定时器。 - 测试时间单位错误:
new Date().getSeconds()获取的是当前时间的秒数(0-59),但setTimeout的第二个参数要求是毫秒数。这会导致测试的时间触发逻辑完全混乱,比如原本想设置30秒后执行,实际变成30毫秒后执行。 - count方法调用冗余:测试代码中调用
tesr.count(1),但count方法定义时不需要参数,不过这只会传递无用参数,不影响核心功能。
修复方案
1. 调整缓存存储结构
修改cache,让每个key对应的值包含实际数据和定时器ID:
function TimeLimitedCache(){ this.cache = {}; this.set = function (key, value, duration) { let result = false; // 存在旧缓存则清除对应定时器 if(key in this.cache){ clearTimeout(this.cache[key].timer); result = true; } // 存储值与定时器ID this.cache[key] = { value: value, timer: setTimeout(() => delete this.cache[key], duration) }; return result; } this.get = function(key){ return this.cache[key] ? this.cache[key].value : -1; } this.count = function(){ return Object.keys(this.cache).length; } }
2. 修正测试时间逻辑
把秒数改为毫秒级时间戳,确保测试时序符合预期:
const start = new Date().getTime(); const tesr = new TimeLimitedCache(); setTimeout(()=>console.log(tesr.set(1,42,50)), start); setTimeout(()=>console.log(tesr.set(1,50,100)), start + 40); setTimeout(()=>console.log(tesr.get(1)), start + 50); setTimeout(()=>console.log(tesr.get(1)), start + 120); setTimeout(()=>console.log(tesr.get(1)), start + 200); setTimeout(()=>console.log(tesr.count()), start + 250);
内容的提问来源于stack exchange,提问作者Akash
相关产品推荐
相关产品推荐

