0

这是我第一次在实际应用中使用while循环,请原谅我的无知。

我正在创建一个网页,展示随着时间的推移使用灯泡的成本。

在这个阶段,我正在尝试使用 while 循环来更新并显示自用户单击电灯开关以来经过的小时数。(1 小时代表 1 秒实时)

当我在萤火虫上设置断点时,一切都正常运行,直到我在我的 while 循环中到达 setTimeout 方法。在它在 setTimeout 方法处中断并单击继续后,它会立即再次在同一位置中断,而没有实际执行任何其他操作。

当我不设置断点时,它会冻结 firefox,我必须停止脚本执行。

我重新检查以确保我正确使用了 setTimeout。现在我什至不确定在哪里检查或搜索什么,因为我不明白出了什么问题。即使只是提示我可能会检查或研究的内容也会非常有帮助。

我试图尽可能详细地注释代码。如果需要,我很乐意澄清一些事情。

我强烈建议您看一下 jsfiddle:

JS小提琴

但这是我的代码:

我的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">&nbsp;</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>
4

4 回答 4

3
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 毫秒运行一个函数。

在计时器运行之间没有代码正在运行!记住这一点很重要。

于 2012-08-29T22:00:05.197 回答
3

JavaScript 使用事件循环。因为您的while循环永远不会产生(#lightswitch'sstate将永远是on因为无限循环锁定 UI,防止用户关闭它),所以事件循环永远不会再次运行,并且您注册的回调setTimeout永远不会有机会执行。

你真正想做的是用一个setInterval函数更新你的计数器。

setInterval(updateNumbers, 1000);
于 2012-08-29T22:00:08.020 回答
1

根据 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(),因为执行setTimeoutor setInterval1 秒并不能确保您每秒都会调用它...

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));
}
于 2012-08-30T01:07:52.420 回答
0

由于 setTimeout 通常优于 setInterval,因此另一种解决方案是

改变

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);

这将每秒检查一次您的灯开关,并在关闭时停止。

于 2012-08-29T22:02:01.860 回答