[英]setTimeout is causing infinite while loop
这是我第一次在实际应用中使用while循环,所以请原谅我的无知。
我正在创建一个网页,演示随着时间的推移使用灯泡的成本。
在此阶段,我正在尝试使用while循环来更新并显示自用户单击电灯开关以来经过的小时数。 (1小时代表实时的1秒)
当我在Firebug上设置断点时,一切正常,直到我进入while循环中的setTimeout方法为止。 在setTimeout方法中断并单击继续后,它立即再次在同一位置中断,而没有实际执行任何其他操作。
当我不设置断点时,它会冻结Firefox,并且我必须停止脚本执行。
我重新检查以确保我正确使用了setTimeout。 现在,我什至不知道在哪里检查或搜索什么,因为我不知道出了什么问题。 即使只是暗示我可能会检查或研究的内容,也将大有帮助。
我试图尽可能冗长地注释代码。 如果需要,我很乐意澄清一些问题。
我强烈建议您看一下jsfiddle:
但是这是我的代码:
我的JS
$(document).ready(function () {
//set image to default off position
$('#lightswitch').css("background-image", "url(http://www.austinlowery.com/graphics/offswitch.png)");
// setup the lifetime hours of the lightbulb for later use
var lifetimeHours = 0;
// setup function to update the calculated lifetime hours number on the webpage to
// be called later
function updateLifetimeHoursHtml (lifetimeHours) {
$('#lifetimeHours').html(lifetimeHours);
}
// set up function to to send to setTimeout
function updateNumbers () {
// increment lifetimeHours by one
lifetimeHours = lifetimeHours++;
// call function to update the webpage with the new number result
updateLifetimeHoursHtml(lifetimeHours);
}
// When the lightswitch on the webpage is clicked, the user should see the
// lifetime hours update every second until the user clicks the switch again
// which will then display the off graphic and pause the updating of the lifetime
// hours
$('#lightswitch').click(function(){
// if the lightswitch is off:
if ($('#lightswitch').attr('state') == 'off') {
// set switch to on
$('#lightswitch').attr('state', 'on');
// update graphic to reflect state change
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/onswitch.png)");
// start updating the lifetime hours number on the webpage
// while the #lightswitch div is in the on state:
while ($('#lightswitch').attr('state') == 'on'){
//call update numbers every second
setTimeout('updateNumbers()', 1000);
}
// the lightswich was not in the off state so it must be on
}else{
// change the state of the switch to off
$('#lightswitch').attr('state', 'off');
// update graphic to reflect state change
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/offswitch.png)");
};
});
});
我的HTML
<div id="container">
<div id="lightswitch" state="off"> </div>
<span>After </span><span id="lifetimehours">0</span><span> lifetime hours:</span>
<br><br>
<span><b>You have spent:</b></span>
<br><br>
<span id="dollaramoutelectricity"></span><span> on electricty</span>
<br>
<span id="mainttime"></span><span> on maintenace</span>
<br>
<span id="dollaramountbulbs"></span><span> on replacement bulbs</span>
<br><br>
<span><b>You have:</b></span>
<br><br>
<span>Produced </span><span id="amountgreenhousegasses"></span><span> of greenhouse gasses</span>
<br>
<span>Sent </span><span id="amounttrash"></span><span> of trash to the dump</span>
<br>
<span>Used </span><span id="amountelectricty"></span><span> of electricity</span>
</div>
var switchTimer;
$('#lightswitch').click(function(){
if ($('#lightswitch').attr('state') == 'off') {
$('#lightswitch').attr('state', 'on');
switchTimer = setInterval(updateNumbers, 1000);
} else {
$('#lightswitch').attr('state', 'off');
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/offswitch.png)");
clearInterval(switchTimer);
};
Javascript是一种基于事件的语言。 这意味着代码不会持续运行。 它仅在发生事件时运行。 通过使用while循环,您基本上已经冻结了它-javascript在该循环中不断运行。 对于像C这样必须一直运行的语言来说,这很好。
但这是JavaScript的错误。 对于javascript,您必须对其进行编码以响应事件,然后停止。 setInterval会不断为您生成一个事件,每隔xx毫秒运行一次函数。
在计时器运行之间,没有代码在运行! 要记住这一点很重要。
JavaScript使用事件循环。 因为您的while
循环永远不会产生( #lightswitch
的state
将永远处于on
state
on
因为无限循环会锁定UI,从而阻止用户对其进行关闭操作),因此事件循环永远不会再次运行,并且您在setTimeout
注册的回调也永远不会机会执行。
您真正要做的是使用setInterval
函数更新计数器。
setInterval(updateNumbers, 1000);
根据yngum的回答,
我认为这样更好:
if ($('#lightswitch').attr('state') == 'off') {
$('#lightswitch').attr('state', 'on');
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/onswitch.png)");
updateNumbers();
}
接着
function updateNumbers () {
lifetimeHours++;
updateLifetimeHoursHtml(lifetimeHours);
if($('#lightswitch').attr('state') == 'on'){
setTimeout(updateNumbers,1000);
}
}
在这里查看: http : //jsfiddle.net/tdS3A/24/
但是,如果要最大精度,则应该存储new Date().getTime()
,因为将setTimeout
或setInterval
为1秒并不能确保每秒都会调用它...
function updateNumbers () {
// call function to update the webpage with the new number result
updateLifetimeHoursHtml(lifetimeHours+(new Date().getTime()-timerStart)/1000);
// call updateNumbers() again
if($('#lightswitch').attr('state') == 'on'){
timer=setTimeout(updateNumbers,1000);
}
}
$('#lightswitch').click(function(){
// if the lightswitch is off:
if ($('#lightswitch').attr('state') == 'off') {
// set switch to on
$('#lightswitch').attr('state', 'on');
// update graphic to reflect state change
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/onswitch.png)");
// update the lifetime hours number on the webpage
timerStart=new Date().getTime();
timer=setTimeout(updateNumbers,1000);
// the lightswich was not in the off state so it must be on
}else{
// change the state of the switch to off
lifetimeHours+=(new Date().getTime()-timerStart)/1000;
clearTimeout(timer);
$('#lightswitch').attr('state', 'off');
// update graphic to reflect state change
$('#lightswitch').css("background-image", "url(http://austinlowery.com/graphics/offswitch.png)");
};
});
在这里查看: http : //jsfiddle.net/tdS3A/26/
即使您希望该数字具有最高的精度,因为您希望计算精确,也可能希望在向用户显示该值时将其舍入。 然后,使用
function updateLifetimeHoursHtml (lifetimeHours) {
$('#lifetimehours').html(Math.round(lifetimeHours));
}
由于通常比setInterval更喜欢setTimeout,因此另一种解决方案是
更改
while ($('#lightswitch').attr('state') == 'on'){
//call update numbers every second
setTimeout('updateNumbers()', 1000);
至
setTimeout(function() {
updateNumbers();
if ($('#lightswitch').attr('state') == 'on')
setTimeout(arguments.callee, 1000);
}, 0);
这将每秒检查一次您的电灯开关,并在其关闭时停止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.