简体   繁体   中英

Infinite loop in while for no aparent reason

I'm working on a timer, and after some answers that I got in this forum it has all been working smoothly. This is what it looks like right now: (just so that you get the idea)

在此输入图像描述

My code (please note that this is a work in progress so some stuff isn't quite finished; basically every function that has a alert("workin"); is still not being used.

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

So this is my problem: In the timerRun() function, I want the timerSubtract() function to repeat while totalTime() > 0 , but the page just crashes if I use a while loop. Why does it do that? I don't think it's an infinit loop. What can I do to do want I want?

Thanks to whoever answers! :-)

The problem is that timerSubtract does it's work using setTimeout .

Every time you use setTimeout you can imagine that it's setting aside that function for later. Then as soon as the program isn't doing anything (and if enough time has passed) then it runs the next function that was set aside. By running a while loop, you never give the runtime a chance to run your functions set aside using setTimeout .

One way of solving this while still using setTimeout would be to do something like this:

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

Instead of using setTimeout, why not use setInterval:

http://jsfiddle.net/ouL1yzpq/

setInterval(function () {
    if(minutes > 0 && seconds == 0) {
        minutes--;
        seconds = 59;
    } else {
        seconds--;
    }
    timerPrint();
}, 1000);

Check this to see how to stop timer: how to stop "setInterval"

The timerSubtract function doesn't change the variables minutes or seconds . It only starts a timeout that would change the variables later on.

If you run the function in a loop waiting for the variables to change, then there will never be any changes to the variables. JavaScript is single threaded, so you have to exit out of the function and return the control to the browser for the timeouts to be executed. While the loop is running the timeout events will not be handled.

If JavaScript would have been multi threaded, then your loop would have started millions of timeouts until a second would have passed and the timeouts would start to execute. As you don't start a timeout once a second but as fast as possible, the timer would instantly count down to minus millions at that time.

Instead of starting a lot of timeouts, use a single setInterval in timerSubtract , and only call the function once. The interval will count down once a second, as I suspect that is how you want your timer to work:

function timerSubtract(inputMinutes, inputSeconds) {
    setInterval(function () {
        if(minutes > 0 && seconds == 0) {
            minutes--;
            seconds = 59;
        } else {
            seconds--;
        }
        timerPrint();
    }, 1000);
}

function timerRun() {
    timerSubtract();
}

As Jonathan posted, you can use setInterval. I would add clearInterval() to his answer to stop at 0 (is that what you want?) Like this:

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

Also, over a long time the timer could be inaccurate. If you want better accuracy, read the actual current system time upon starting the timer, then at each interval, read the actual time again and subtract the two values (current - start) to get the actual elapsed time. Then subtract the elapsed time from the initial total to get the current time remaining.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM