没有明显原因的无限循环
Infinite loop in while for no aparent reason
我正在开发一个计时器,在我在这个论坛上得到一些答案后,它一直运行得很顺利。这就是它现在的样子:(只是为了让你明白)
我的代码(请注意,这是一项正在进行的工作,所以有些东西还没有完全完成;基本上每个具有 alert("workin");
的函数仍然没有被使用。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>WIP</title>
<meta charset="UFT-8">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<script>
$(document).ready(function() {
timerSet(9,12);
timerRun();
});
function timerReset() {
alert("workin");
}
function timerSet(inputMinutes, inputSeconds) {
minutes = inputMinutes;
seconds = inputSeconds;
finalTimeInSeconds = minutes*60 + seconds; //finalTimeInSeconds is the time it takes for the timer to be 00:00 in seconds.
timerPrint();
}
function timerAdd(inputMinutes, inputSeconds) {
alert("workin");
}
function timerSubtract(inputMinutes, inputSeconds) {
setTimeout(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
}
function timerRun() {
timerSubtract();
}
function timerStop() {
alert("workin");
}
function timerPrint() {
displayMinutes = (minutes.toString().length == 2) ? minutes : "0" + minutes; //ternary operator: adds a zero to the beggining
displaySeconds = (seconds.toString().length == 2) ? seconds : "0" + seconds; //of the number if it has only one caracter.
$("#timerText").text(displayMinutes + ":" + displaySeconds);
}
function totalTime() {
var totalTimeInSeconds = minutes*60 + seconds;
return totalTimeInSeconds; //totalTimeInSeconds is the time that the timer now displays in seconds.
}
</script>
</head>
<body>
<div id="timerText">00:00</div>
</body>
</html>
所以这是我的问题:在 timerRun()
函数中,我希望 timerSubtract()
函数重复 while totalTime() > 0
,但是如果我使用 while 循环,页面就会崩溃。为什么要这样做?我不认为这是一个无限循环。我可以做些什么来做我想做的事?
感谢回答者! :-)
问题是 timerSubtract
使用 setTimeout
可以正常工作。
每次使用 setTimeout
时,您都可以想象它正在为以后保留该功能。然后,一旦程序没有做任何事情(并且如果已经过了足够的时间),那么它 运行 就是下一个被搁置的函数。通过 运行 一个 while
循环,你永远不会给 运行 时间一个机会 运行 使用 setTimeout
.
搁置的函数
在仍然使用 setTimeout
的情况下解决此问题的一种方法是执行以下操作:
function timerRun() {
if (minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
// Queue up timerRun to run again in 1 second
setTimeout(timerRun, 1000);
}
timerRun();
为什么不使用 setInterval 而不是使用 setTimeout:
setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
检查这个以了解如何停止计时器:how to stop "setInterval"
timerSubtract
函数不会更改变量 minutes
或 seconds
。它只会启动一个超时,稍后会更改变量。
如果您 运行 循环中的函数等待变量发生变化,那么变量将永远不会发生任何变化。 JavaScript 是单线程的,因此您必须退出该函数,并且 return 将控件交给浏览器以执行超时。当循环处于 运行 时,将不会处理超时事件。
如果 JavaScript 是多线程的,那么您的循环将开始数百万次超时,直到一秒钟过去并且超时将开始执行。由于您不是每秒开始一次超时,而是尽可能快地开始,计时器会立即倒计时到负百万。
与其启动大量超时,不如在 timerSubtract
中使用单个 setInterval
,并且只调用函数一次。间隔将每秒倒计时一次,因为我怀疑这就是您希望计时器工作的方式:
function timerSubtract(inputMinutes, inputSeconds) {
setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
}
function timerRun() {
timerSubtract();
}
正如 Jonathan 所说,您可以使用 setInterval。我会在他的回答中添加 clearInterval() 以在 0 处停止(这是你想要的吗?)
像这样:
function timerSubtract(inputMinutes, inputSeconds) {
var countdown = setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
if( totalTime() <= 0){
clearInterval(countdown);
// timer is done, do something interesting..
}
timerPrint();
}, 1000);
}
此外,时间长了计时器可能会不准确。如果您想要更高的准确性,请在启动计时器时读取实际的当前系统时间,然后在每个时间间隔再次读取实际时间并减去两个值(当前 - 开始)以获得实际经过的时间。然后从初始总计中减去经过的时间,得到当前剩余时间。
我正在开发一个计时器,在我在这个论坛上得到一些答案后,它一直运行得很顺利。这就是它现在的样子:(只是为了让你明白)
我的代码(请注意,这是一项正在进行的工作,所以有些东西还没有完全完成;基本上每个具有 alert("workin");
的函数仍然没有被使用。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>WIP</title>
<meta charset="UFT-8">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<script>
$(document).ready(function() {
timerSet(9,12);
timerRun();
});
function timerReset() {
alert("workin");
}
function timerSet(inputMinutes, inputSeconds) {
minutes = inputMinutes;
seconds = inputSeconds;
finalTimeInSeconds = minutes*60 + seconds; //finalTimeInSeconds is the time it takes for the timer to be 00:00 in seconds.
timerPrint();
}
function timerAdd(inputMinutes, inputSeconds) {
alert("workin");
}
function timerSubtract(inputMinutes, inputSeconds) {
setTimeout(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
}
function timerRun() {
timerSubtract();
}
function timerStop() {
alert("workin");
}
function timerPrint() {
displayMinutes = (minutes.toString().length == 2) ? minutes : "0" + minutes; //ternary operator: adds a zero to the beggining
displaySeconds = (seconds.toString().length == 2) ? seconds : "0" + seconds; //of the number if it has only one caracter.
$("#timerText").text(displayMinutes + ":" + displaySeconds);
}
function totalTime() {
var totalTimeInSeconds = minutes*60 + seconds;
return totalTimeInSeconds; //totalTimeInSeconds is the time that the timer now displays in seconds.
}
</script>
</head>
<body>
<div id="timerText">00:00</div>
</body>
</html>
所以这是我的问题:在 timerRun()
函数中,我希望 timerSubtract()
函数重复 while totalTime() > 0
,但是如果我使用 while 循环,页面就会崩溃。为什么要这样做?我不认为这是一个无限循环。我可以做些什么来做我想做的事?
感谢回答者! :-)
问题是 timerSubtract
使用 setTimeout
可以正常工作。
每次使用 setTimeout
时,您都可以想象它正在为以后保留该功能。然后,一旦程序没有做任何事情(并且如果已经过了足够的时间),那么它 运行 就是下一个被搁置的函数。通过 运行 一个 while
循环,你永远不会给 运行 时间一个机会 运行 使用 setTimeout
.
在仍然使用 setTimeout
的情况下解决此问题的一种方法是执行以下操作:
function timerRun() {
if (minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
// Queue up timerRun to run again in 1 second
setTimeout(timerRun, 1000);
}
timerRun();
为什么不使用 setInterval 而不是使用 setTimeout:
setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
检查这个以了解如何停止计时器:how to stop "setInterval"
timerSubtract
函数不会更改变量 minutes
或 seconds
。它只会启动一个超时,稍后会更改变量。
如果您 运行 循环中的函数等待变量发生变化,那么变量将永远不会发生任何变化。 JavaScript 是单线程的,因此您必须退出该函数,并且 return 将控件交给浏览器以执行超时。当循环处于 运行 时,将不会处理超时事件。
如果 JavaScript 是多线程的,那么您的循环将开始数百万次超时,直到一秒钟过去并且超时将开始执行。由于您不是每秒开始一次超时,而是尽可能快地开始,计时器会立即倒计时到负百万。
与其启动大量超时,不如在 timerSubtract
中使用单个 setInterval
,并且只调用函数一次。间隔将每秒倒计时一次,因为我怀疑这就是您希望计时器工作的方式:
function timerSubtract(inputMinutes, inputSeconds) {
setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
timerPrint();
}, 1000);
}
function timerRun() {
timerSubtract();
}
正如 Jonathan 所说,您可以使用 setInterval。我会在他的回答中添加 clearInterval() 以在 0 处停止(这是你想要的吗?) 像这样:
function timerSubtract(inputMinutes, inputSeconds) {
var countdown = setInterval(function () {
if(minutes > 0 && seconds == 0) {
minutes--;
seconds = 59;
} else {
seconds--;
}
if( totalTime() <= 0){
clearInterval(countdown);
// timer is done, do something interesting..
}
timerPrint();
}, 1000);
}
此外,时间长了计时器可能会不准确。如果您想要更高的准确性,请在启动计时器时读取实际的当前系统时间,然后在每个时间间隔再次读取实际时间并减去两个值(当前 - 开始)以获得实际经过的时间。然后从初始总计中减去经过的时间,得到当前剩余时间。