
本文详解 Simon 游戏开发中 roundList 数组长度异常翻倍的根本原因——重复调用 setInterval 未清理前序定时器,并提供可立即落地的修复方案与最佳实践。
本文详解 simon 游戏开发中 `roundlist` 数组长度异常翻倍的根本原因——重复调用 `setinterval` 未清理前序定时器,并提供可立即落地的修复方案与最佳实践。
在实现 Simon 游戏时,roundList 本应每轮仅追加一个随机颜色(如 ['green', 'red']),但实际却出现长度翻倍(如变为 ['green', 'red', 'green', 'red'])。问题并非出在 .push() 逻辑本身,而是定时器管理失控导致 randomColor() 被重复、并发执行。
核心症结在于 nextRound() 函数中的定时器使用方式:
function nextRound() {
let delay = 500 * roundList.length;
let repeat = setInterval(randomColor, 500); // ❌ 每次调用都新建一个 interval
setTimeout(repeat, delay); // ⚠️ 此处语法错误:setTimeout 第一个参数应为函数,而非 interval ID
setTimeout(stop, delay);
}
这段代码存在两个致命问题:
- 未清除旧定时器:每次调用 nextRound() 都会创建新的 setInterval,而旧的仍在运行,导致 randomColor() 被多个定时器同时触发;
- setTimeout(repeat, delay) 语义错误:repeat 是 setInterval 返回的数值型 ID,不能作为回调函数传入 setTimeout,该行实际无效,且掩盖了真正的清理逻辑。
✅ 正确做法是:全局声明定时器引用,每次启动新轮次前先清除旧定时器。修改如下:
let repeat; // 全局声明,用于存储当前 interval ID
function nextRound() {
clearInterval(repeat); // ✅ 关键:先清除可能存在的旧定时器
const delay = 500 * roundList.length;
console.log(`本轮延迟: ${delay}ms`);
repeat = setInterval(randomColor, 500); // ✅ 启动新定时器
setTimeout(() => clearInterval(repeat), delay); // ✅ 到时自动停止(替代原 stop 函数)
}
同时,建议移除 randomColor() 中重复的 roundList.push(expectedInput) —— 它已在 nextRound() 的首次调用中被正确触发,避免因定时器叠加造成多次 push。
? 进阶优化提示:
- 将 expectedInput 改为数组索引比对(如 roundList[roundIndex] === actualInput),提升逻辑健壮性;
- 使用 requestAnimationFrame 替代 setTimeout 实现更精准的视觉反馈同步;
- 为 randomColor() 添加防抖机制,防止用户快速点击导致状态错乱。
修复后,roundList 将严格按游戏轮次线性增长([green] → [green, red] → [green, red, blue]),为后续校验、动画序列和难度递增奠定可靠基础。











