如何在同一个函数中使用 setInterval() 和 clearInterval()
How to use setInterval() and clearInterval() in the same function
我正在尝试创建一个启动和停止计时器的函数。启动总是在单击按钮时,但停止可能是由于计时器 运行 关闭或从另一个函数再次调用该函数。
这就是我目前所拥有的。非常适合您所看到的,但我无法弄清楚如何合并 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; // define `count` globaly
let timer = document.getElementById('timer')
const timerStop = () => {
clearInterval(intervalId)
}
const timerRestart = () => {
timerStop()
timer.innerHTML = 100;
}
const timerStart = () => {
timerStop(); // Stop timer by security, e.g. if you call `timerStart()` multiple times
intervalId = setInterval(() => {
let timeLeft = timer.innerHTML;
if (+timeLeft > 0) {
timer.innerHTML = +timeLeft - 1
} else {
timerRestart();
gameOverMessage()
}
}, 1000)
}
<div id="timer">100</div>
<div>
<button onclick="timerStart()">Start</button>
<button onclick="timerStop()">Pause</button>
<button onclick="timerRestart()">Restart</button>
</div>
setInterval
根据您指定的时间间隔,尽量space回调运行ning。问题是:在游戏中,您真正想要的是将世界的当前状态以流畅及时的方式打印到屏幕上。这与setInterval
的行为不同,对屏幕一无所知,盲目重复调用。
例如:如果您在浏览器选项卡中开始 setInterval(foo, 100)
游戏,然后导航到浏览器中的另一个选项卡,请等待十秒钟,然后 return 进入您的游戏,您的 foo
回调 将被快速连续调用大约一百次 因为排队的回调是 "drained"。您不太可能想要这种行为。
requestAnimationFrame
是一个更好的解决方案,因为它仅在(不久前)您的游戏被渲染时调用 - 这正是您想要的。
在下面的代码中,createTimer
创建了一个定时器对象。计时器有 start
、stop
和 toggle
方法。
start
方法记录它何时被调用并触发 requestAnimationFrame
,提供一个名为 tick
的回调。每次报价发生时,我们 运行 一些逻辑来查看要调用哪个(如果有的话)回调。
如果经过的时间大于或等于计时器的 duration
,则调用 onTimeout
回调并停止计时器。
如果经过的时间小于 duration
,但大于或等于 interval
,那么我们更新 lastInterval
并调用 onInterval
回调。
否则我们只需提示计时器的另一个滴答声。
stop
方法简单地使用请求动画ID来取消定时器cancelAnimationFrame
。
function createTimer() {
let rafId = null
function start({duration = 10000, interval = 1000, onInterval, onTimeout, onStop, startTime=performance.now(), lastInterval = startTime}) {
function tick(now=performance.now()) {
const elapsed = now - startTime
if (elapsed >= duration) {
cancelAnimationFrame(rafId)
rafId = null
return onTimeout()
}
if ((now - lastInterval) >= interval) {
lastInterval = now
onInterval({
duration,
elapsed
})
}
rafId = requestAnimationFrame(tick)
}
rafId = requestAnimationFrame(tick)
}
function stop() {
cancelAnimationFrame(rafId)
rafId = null
return onStop()
}
function toggle(...args) {
rafId ? stop() : start(...args)
}
const timer = {
start,
stop,
toggle
}
return timer
}
const timer = createTimer()
const onInterval = ({duration, elapsed})=>console.log(`Remaining: ${((duration - elapsed)/1000).toFixed(0)}`)
const onTimeout = ()=>console.log('Timed out.')
const onStop = ()=>console.log('Manually stopped.')
document.getElementById('btn').addEventListener('click', () => timer.toggle({
onInterval,
onTimeout,
onStop
}))
<button id="btn">Toggle Timer</button>
我正在尝试创建一个启动和停止计时器的函数。启动总是在单击按钮时,但停止可能是由于计时器 运行 关闭或从另一个函数再次调用该函数。
这就是我目前所拥有的。非常适合您所看到的,但我无法弄清楚如何合并 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; // define `count` globaly
let timer = document.getElementById('timer')
const timerStop = () => {
clearInterval(intervalId)
}
const timerRestart = () => {
timerStop()
timer.innerHTML = 100;
}
const timerStart = () => {
timerStop(); // Stop timer by security, e.g. if you call `timerStart()` multiple times
intervalId = setInterval(() => {
let timeLeft = timer.innerHTML;
if (+timeLeft > 0) {
timer.innerHTML = +timeLeft - 1
} else {
timerRestart();
gameOverMessage()
}
}, 1000)
}
<div id="timer">100</div>
<div>
<button onclick="timerStart()">Start</button>
<button onclick="timerStop()">Pause</button>
<button onclick="timerRestart()">Restart</button>
</div>
setInterval
根据您指定的时间间隔,尽量space回调运行ning。问题是:在游戏中,您真正想要的是将世界的当前状态以流畅及时的方式打印到屏幕上。这与setInterval
的行为不同,对屏幕一无所知,盲目重复调用。
例如:如果您在浏览器选项卡中开始 setInterval(foo, 100)
游戏,然后导航到浏览器中的另一个选项卡,请等待十秒钟,然后 return 进入您的游戏,您的 foo
回调 将被快速连续调用大约一百次 因为排队的回调是 "drained"。您不太可能想要这种行为。
requestAnimationFrame
是一个更好的解决方案,因为它仅在(不久前)您的游戏被渲染时调用 - 这正是您想要的。
在下面的代码中,createTimer
创建了一个定时器对象。计时器有 start
、stop
和 toggle
方法。
start
方法记录它何时被调用并触发 requestAnimationFrame
,提供一个名为 tick
的回调。每次报价发生时,我们 运行 一些逻辑来查看要调用哪个(如果有的话)回调。
如果经过的时间大于或等于计时器的 duration
,则调用 onTimeout
回调并停止计时器。
如果经过的时间小于 duration
,但大于或等于 interval
,那么我们更新 lastInterval
并调用 onInterval
回调。
否则我们只需提示计时器的另一个滴答声。
stop
方法简单地使用请求动画ID来取消定时器cancelAnimationFrame
。
function createTimer() {
let rafId = null
function start({duration = 10000, interval = 1000, onInterval, onTimeout, onStop, startTime=performance.now(), lastInterval = startTime}) {
function tick(now=performance.now()) {
const elapsed = now - startTime
if (elapsed >= duration) {
cancelAnimationFrame(rafId)
rafId = null
return onTimeout()
}
if ((now - lastInterval) >= interval) {
lastInterval = now
onInterval({
duration,
elapsed
})
}
rafId = requestAnimationFrame(tick)
}
rafId = requestAnimationFrame(tick)
}
function stop() {
cancelAnimationFrame(rafId)
rafId = null
return onStop()
}
function toggle(...args) {
rafId ? stop() : start(...args)
}
const timer = {
start,
stop,
toggle
}
return timer
}
const timer = createTimer()
const onInterval = ({duration, elapsed})=>console.log(`Remaining: ${((duration - elapsed)/1000).toFixed(0)}`)
const onTimeout = ()=>console.log('Timed out.')
const onStop = ()=>console.log('Manually stopped.')
document.getElementById('btn').addEventListener('click', () => timer.toggle({
onInterval,
onTimeout,
onStop
}))
<button id="btn">Toggle Timer</button>