簡體   English   中英

setTimeout導致無限的while循環

[英]setTimeout is causing infinite while loop

這是我第一次在實際應用中使用while循環,所以請原諒我的無知。

我正在創建一個網頁,演示隨着時間的推移使用燈泡的成本。

在此階段,我正在嘗試使用while循環來更新並顯示自用戶單擊電燈開關以來經過的小時數。 (1小時代表實時的1秒)

當我在Firebug上設置斷點時,一切正常,直到我進入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>
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循環永遠不會產生( #lightswitchstate將永遠處於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() ,因為將setTimeoutsetInterval為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM