Pomodoro时钟Start按钮异常:多次点击致计时器加速的原因与解决
Pomodoro时钟多次点击Start按钮加速的问题解惑
我正在开发一款Pomodoro时钟,目前代码尚未完善,但发现Start按钮存在异常:单次点击可正常启动计时器,但若多次快速点击,计时器会疯狂加速。请问这是什么原因?该如何避免?
你的代码片段
HTML
<div id="title">POMODORO </div> <div id="conteneur2"> <div class="txt" id="damn1">Pause</div> <div class="txt" id="damn">Length of sessions</div> </div> <div id="supercont1"> <div id="conteneur"> <div class="el1"><input class="buto" type="button" value="-1 minute" onclick='minusOne(this)' /></div> <div id="output" class="el"></div> <div class="el1"><input class="buto" type="button" value='+1 Minute' onclick='addOne(this)' /></div> <div id="min1" class="el"> </div> <div id="sec" class="el"> </div> <div id="start"><input class="buto" type="button" id="bouton" value="START" onclick='doSomething()' /></div> <div class="el"><input class="buto" type="button" value='-1 Minute' onclick='minusOne1(this)' /></div> <div id="output2" class="el1"></div> <div class="el"><input class="buto" type="button" value='+1 Minute' onclick='addOne1(this)' /></div> </div> </div>
CSS
#damn1 { padding-left: 50px; } #damn { padding-left: 450px; } #conteneur2 { display: flex; } .txt { color: #ffcf40; font-size: 45px; } .buto { border-radius: 50px; background: #ffcf40; text-decoration: none; } #output { font-size: 100px; } #output2 { font-size: 100px; } #bouton { height: 100px; width: 100px; margin-top: 200px; } #min1 { margin-top: 200px; font-size: 100px; color: #ffcf40; } #sec { color: #ffcf40; margin-top: 200px; font-size: 100px; } body { background: black; } #cont1 { display: flex; justify-content: center; } #conteneur { margin-top: 50px; display: flex; justify-content: center; } .el { width: 100px; height: 100px; color: #ffcf40; } .el1 { width: 100px; height: 100px; color: #ffcf40; } #title { margin: 0 auto; text-align: center; }
JavaScript
let pause = "5"; let duree = "25"; let min = "5"; let nb = 0; let go; document.getElementById("output").innerHTML = pause; document.getElementById("output2").innerHTML = duree; function addOne(btn) { pause = pause + " + 1"; console.log(pause); clearTimeout(go); document.getElementById("output").innerHTML = eval(pause); pause = eval(pause); } function minusOne(btn) { clearTimeout(go); if (eval(pause) == 0) { pause = pause + ""; } else { pause = pause + " - 1"; } document.getElementById("output").innerHTML = eval(pause); pause = eval(pause); } function addOne1(btn) { clearTimeout(go); min = min + " + 1"; document.getElementById("output2").innerHTML = eval(min); document.getElementById("min1").innerHTML = eval(min) + ":"; min = eval(min); } function minusOne1(btn) { if (eval(duree) == 0) { duree = duree + ""; } else { min = min + " - 1"; } document.getElementById("output2").innerHTML = eval(min); document.getElementById("min1").innerHTML = eval(min) + ":"; clearTimeout(go); min = eval(min); } document.getElementById("min1").innerHTML = min + ":"; document.getElementById("sec").innerHTML = " " + nb; function doSomething() { if (nb > 0) { nb = nb - 1; } else if (min > 0) { nb = 59; min--; } else { min = pause } go = setTimeout(doSomething, 1000); document.getElementById("min1").innerHTML = min + ":"; document.getElementById("sec").innerHTML = nb; }
问题原因
这个问题其实很好理解:每次点击START按钮,就会调用一次doSomething()函数,而这个函数内部又会通过setTimeout(doSomething, 1000)创建一个新的定时器,让它1秒后再次执行自己。
如果多次快速点击,就会同时创建多个独立的定时器,这些定时器不会互相干扰,都会按时触发倒计时逻辑。原本每秒只执行一次的操作,现在变成每秒执行好几次,看起来计时器就疯狂加速了。
而且你的代码里虽然有clearTimeout(go),但只在调整时间的按钮里调用,点击START时并没有先清除之前可能存在的定时器,所以旧的定时器一直在运行,新的又不断叠加,自然就乱了。
解决方法
我们需要做两件核心事情:一是每次启动计时器前先清除之前的定时器,二是加个状态标记防止重复触发(避免无效的多次点击)。
修改后的JavaScript代码
let pause = 5; // 直接改成数字类型,避免使用eval let duree = 25; let min = 5; let nb = 0; let go; let isRunning = false; // 标记计时器是否正在运行 document.getElementById("output").innerHTML = pause; document.getElementById("output2").innerHTML = duree; function addOne(btn) { clearTimeout(go); pause += 1; // 直接数字相加,安全又简单 document.getElementById("output").innerHTML = pause; } function minusOne(btn) { clearTimeout(go); if (pause > 0) { pause -= 1; } document.getElementById("output").innerHTML = pause; } function addOne1(btn) { clearTimeout(go); min += 1; document.getElementById("output2").innerHTML = min; document.getElementById("min1").innerHTML = min + ":"; } function minusOne1(btn) { clearTimeout(go); if (min > 0) { min -= 1; } document.getElementById("output2").innerHTML = min; document.getElementById("min1").innerHTML = min + ":"; } document.getElementById("min1").innerHTML = min + ":"; document.getElementById("sec").innerHTML = " " + nb; // 新增专门的启动函数,代替直接调用doSomething function startTimer() { if (isRunning) return; // 如果已经在运行,直接返回,不重复启动 isRunning = true; clearTimeout(go); // 先清除之前的定时器,确保只有一个在运行 doSomething(); } function doSomething() { if (nb > 0) { nb -= 1; } else if (min > 0) { nb = 59; min -= 1; } else { min = pause; // 这里可以添加休息时间的提示逻辑 } document.getElementById("min1").innerHTML = min + ":"; document.getElementById("sec").innerHTML = nb; go = setTimeout(doSomething, 1000); }
修改HTML中的START按钮
把原来的onclick='doSomething()'改成onclick='startTimer()':
<div id="start"><input class="buto" type="button" id="bouton" value="START" onclick='startTimer()' /></div>
额外小建议
- 我把所有
eval()都去掉了,因为它不仅性能差,还存在安全风险,直接把变量定义成数字类型,加减操作更简单安全。 - 你还可以添加一个暂停按钮,点击时执行
clearTimeout(go)并把isRunning设为false,让计时器功能更完整。
内容的提问来源于stack exchange,提问作者Jukker
相关产品推荐
相关产品推荐

