Javascript 如何在同一个函数中使用setInterval()和clearInterval()

Javascript 如何在同一个函数中使用setInterval()和clearInterval(),javascript,if-statement,setinterval,clearinterval,Javascript,If Statement,Setinterval,Clearinterval,我正在尝试创建一个启动和停止计时器的函数。启动总是在单击按钮时进行,但停止可能是由于计时器停止运行或从另一个函数再次调用该函数 这就是我目前所拥有的。对于您所看到的内容,它非常适合,但我不知道如何合并clearInterval(),以便在游戏获胜时停止。正在运行的调用timerCountdown位于不同的js文件中。我读过类似问题的答案,但他们似乎都在做一些不同的事情,我不能让它为我的案件工作 我确实意识到我需要调用clearInterval(count),但我不知道如何将其合并到函数本身中 c

我正在尝试创建一个启动和停止计时器的函数。启动总是在单击按钮时进行,但停止可能是由于计时器停止运行或从另一个函数再次调用该函数

这就是我目前所拥有的。对于您所看到的内容,它非常适合,但我不知道如何合并clearInterval(),以便在游戏获胜时停止。正在运行的调用timerCountdown位于不同的js文件中。我读过类似问题的答案,但他们似乎都在做一些不同的事情,我不能让它为我的案件工作

我确实意识到我需要调用clearInterval(count),但我不知道如何将其合并到函数本身中

const timerCountdown = () => {                             
  let count = setInterval(() => {
    let timeLeft = timer.innerHTML
    if (timeLeft > 0) {
      timer.innerHTML = timeLeft - 1
    } else {
      gameOverMessage()
    }
  }, 1000) 
}

如果赢了或没有时间可用,可以使用全局变量
intervalId
并清除间隔计时器

var intervalId;

const timerCountdown = () => {                             
    intervalId = setInterval(() => {
        let timeLeft = timer.innerHTML
        if (timeLeft > 0) {
            timer.innerHTML = timeLeft - 1
        } else {
            clearInterval(intervalId);
            gameOverMessage();
        }
    }, 1000) 
  },
  won = () => {
      clearInterval(intervalId);
      // additional code
  };

您需要在全局变量中推送间隔id。这样,您可以在需要时使用另一个函数来停止间隔

let intervalId;//全局定义“count”
让timer=document.getElementById('timer'))
常数timerStop=()=>{
clearInterval(有效期间)
}
常量timerRestart=()=>{
timerStop()
timer.innerHTML=100;
}
常量timerStart=()=>{
timerStop();//通过安全性停止计时器,例如,如果多次调用'timerStart()'
intervalId=setInterval(()=>{
让timeLeft=timer.innerHTML;
如果(+时间间隔>0){
timer.innerHTML=+timeLeft-1
}否则{
timerRestart();
gameOverMessage()
}
}, 1000)
}
100
开始
暂停
重新启动

setInterval
尽最大努力根据指定的间隔来分配回调的运行空间。问题是:在游戏中,你真正想要的是将当前世界的状态以平滑及时的方式打印到屏幕上。这与
setInterval
的行为不同,后者对屏幕一无所知,并被盲目地重复调用

例如:如果您在浏览器选项卡中启动游戏的
setInterval(foo,100)
,然后导航到浏览器中的另一个选项卡,等待十秒钟,然后返回游戏,您的
foo
callback将被快速连续调用大约一百次,因为排队的回调被“耗尽”。您不太可能想要这种行为

这是一个更好的解决方案,因为它只在(不久之前)渲染游戏时调用-这是您想要的

在以下代码中,计时器对象由
createTimer
创建。计时器具有
启动
停止
切换
方法

start
方法记录调用它的时间并触发
requestAnimationFrame
,提供一个名为
tick
的回调。每次出现滴答声时,我们都会运行一些逻辑来查看要调用哪个(如果有的话)回调

如果经过的时间大于或等于计时器的
持续时间
,则调用
onTimeout
回调并停止计时器

如果经过的时间小于
持续时间
,但大于或等于
间隔
期间,则更新
lastInterval
并调用
onInterval
回调

否则,我们只需提示计时器的另一个滴答声

stop
方法仅使用请求动画ID来使用
cancelAnimationFrame
取消计时器

函数createTimer(){
设rafId=null
函数开始({duration=10000,interval=1000,onInterval,onTimeout,onStop,startTime=performance.now(),lastInterval=startTime}){
函数勾选(now=performance.now()){
const appeased=now-startTime
如果(经过>=持续时间){
取消动画帧(rafId)
rafId=null
return-onTimeout()
}
如果((现在-上次间隔)>=间隔){
lastInterval=现在
内部({
期间
逝去
})
}
rafId=requestAnimationFrame(勾选)
}
rafId=requestAnimationFrame(勾选)
}
函数停止(){
取消动画帧(rafId)
rafId=null
返回顶部()
}
函数切换(…参数){
rafId?停止():开始(…参数)
}
常数计时器={
开始
停止
切换
}
返回计时器
}
const timer=createTimer()
const onInterval=({duration,appeased})=>console.log(`Remaining:${((duration-appeased)/1000).toFixed(0)}`)
const onTimeout=()=>console.log('超时')
const onStop=()=>console.log('手动停止')
document.getElementById('btn')。addEventListener('click',()=>timer.toggle({
在区间,
及时,
顶上
}))

切换计时器
因此需要从外部访问
让计数
。(另外,
setInterval
不准确)并且
timeLeft
是一个字符串,而不是一个数字。您可以向我们展示您的其他函数吗?因此,如果再次调用
timerCountdown
,则倒计时停止并再次开始?@epascarello-为什么setInterval不准确?的确,timeLeft是一个字符串,但它工作得很好,所以我认为没有必要将其转换为数字。由于let和const没有被提升,所以最好在之前移动timerStoptimeStart@MosèRaguzzini谢谢,我添加了一个实时演示,我移动了
timerStop