简体   繁体   中英

In a While loop setTimeout not working

I am 11 and just started programming. I was trying to use a while loop and I want it to display the answers in blocks instead of one huge chunk. So i tried to use a setTimeout but it would just display the first line after a second then instantly display the rest as a huge chunk. Also it would then use the number 9 as the temp variable even though i got no idea where that came from.Thanks in advance.

I would like to keep the while loop in the code because I am learning how to use them , so if you could keep the while statement in your answer that would be awesome!

here is my code:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Made with Thimble</title>
    <link rel="stylesheet">
</head>

<body bgcolor="lightblue">
    <div id="d2">
        Divisible by 2
    </div>
    <div id="d3">
        Divisible by 3
    </div>
    <div>
        <input id="seed" type="number" placeholder="seed" value="3"><br>
        <input id="max" type="number" placeholder="max" value="8">
    </div>
    <button onclick="count()">Count</button>
    <div id="output"></div>
    <script>
    function count() {

        var seed = document.getElementById("seed").value
        var max = document.getElementById("max").value
        var temp = 1
        var output = document.getElementById("output")
        temp = seed
        console.log("seed:" + seed)
        console.log("max:" + max)
        document.getElementById("output").innerHTML = " "
        while (temp <= max) {

            var intdivby2 = temp % 2
            var intdivby3 = temp % 3

            setTimeout(function() {
                document.getElementById("output").innerHTML += "remainder of " + temp + " divided 
                by 2 is: "+intdivby2.toString()+" < br > "
                document.getElementById("output").innerHTML += "remainder of " + temp + " divided 
                by 3 is: "+intdivby3.toString()+" < br > "
                temp++
            }, 1000)

        }
    }
    </script>
</body>
</html>

Mixing loops with timeouts is a bad idea, instead use an interval and delete it when the condition is no longer true

var intervalId = setInterval(function () {
    var intdivby2 = temp % 2;
    var intdivby3 = temp % 3;
    document.getElementById("output").innerHTML += "remainder of " + temp + " divided by 2 is: " + intdivby2.toString() + " <br/> ";
    document.getElementById("output").innerHTML += "remainder of " + temp + " divided by 3 is: " + intdivby3.toString() + " <br/> ";
    if (++temp > max) clearInterval(intervalId);
}, 1000);

Small Example

 var index = 0; var intervalId = setInterval(function() { var text = "Iteration: " + index + "<br/>"; document.getElementById("output").innerHTML += text; if (++index > 10) clearInterval(intervalId); }, 1000); 
 #output { max-height: calc(100vh - 130px); overflow: auto; } 
 <div id="output"></div> 

Another way would be to use recursive timeouts

(function asyncLoop() {
    setTimeout(function () {
        var intdivby2 = temp % 2;
        var intdivby3 = temp % 3;
        document.getElementById("output").innerHTML += "remainder of " + temp + " divided by 2 is: " + intdivby2.toString() + " <br/>";
        document.getElementById("output").innerHTML += "remainder of " + temp + " divided by 3 is: " + intdivby3.toString() + " <br/>";
        if (++temp <= max) asyncLoop();
    }, 1000);
})();

Small Example

 var index = 0; (function asyncLoop() { setTimeout(function() { var text = "Iteration: " + index + "<br/>"; document.getElementById("output").innerHTML += text; if (++index <= 10) asyncLoop(); }, 1000); })(); 
 #output { max-height: calc(100vh - 130px); overflow: auto; } 
 <div id="output"></div> 

I see what you're trying to do there, but unfortunately it won't work the way you're thinking.

A setTimeout() doesn't pause the rest of your code, it simply says "wait this amount of time before running the stuff inside me", and meanwhile the rest of the script will keep chugging along. So instead of a one second delay between each step of the loop, your loop runs through its entire set one right after another, then one second later all of your setTimeouts fire one right after another.

A more typical way in javascript to do what you want (cause a chunk of code to run repeatedly with a delay between each repetition) is setInterval() -- it works almost exactly like setTimeout() except that it keeps firing every time the interval expires (until you cancel it with clearInterval() .) For example:

 function count() { var seed = document.getElementById("seed").value var max = document.getElementById("max").value var temp = 1 var output = document.getElementById("output") temp = seed // you already captured the "output" node, so we can reuse it here (and below). output.innerHTML = " " var theInterval = setInterval(function() { var intdivby2 = temp % 2 var intdivby3 = temp % 3 // no need to call .toString() on these vars; the fact that we're // adding them to another string will cause that to happen automatically output.innerHTML += "remainder of " + temp + " divided by 2 is: "+intdivby2+" <br> " output.innerHTML += "remainder of " + temp + " divided by 3 is: "+intdivby3+" <br> " temp++ if (temp > max) { clearInterval(theInterval); // this stops the loop } }, 1000); } 
 <div> <input id="seed" type="number" placeholder="seed" value="3"><br> <input id="max" type="number" placeholder="max" value="8"> </div> <button onclick="count()">Count</button> <div id="output"></div> 

Just as an exercise, though, it is possible to combine while and setTimeout by changing the duration of each setTimeout as you step through the loop -- this way you're starting up all the setTimeouts simultaneously (almost), but increasing the amount of time each one waits before it fires.

But there's a catch: you need each setTimeout to use different values for temp . If you try to handle this all in one function, by the time the first setTimeout fires, the while loop has already incremented the variables all the way through the loop, so every setTimeout ends up using the value from what should have been the last iteration. (You had this same problem in your code, too: that's why you were seeing '9' on the first iteration.)

If you try to solve that by waiting to increment the variables until inside the setTimeout, you just wind up with an endless loop, because the first increment doesn't happen until the first setTimeout fires. So that's no good either. (Endless loops are often what happens when you use while , which is why I avoid using it under pretty much any circumstances.)

You can solve this by instead calling a second function with the specific values you need for each iteration, and having that secondary function set up its own timeout with its own duration:

 function count() { var seed = document.getElementById("seed").value var max = document.getElementById("max").value var temp = seed var i = 1 // or use 0 to have the first iteration fire immediately while (temp <= max) { handleIteration(temp, i); temp++ i++ } } function handleIteration(temp, i) { // temp and i are safely scoped within this function now, we don't // need to worry about the while loop changing them setTimeout(function() { var intdivby2 = temp % 2 var intdivby3 = temp % 3 var output = document.getElementById('output') output.innerHTML += "remainder of " + temp + " divided by 2 is: " + intdivby2 + " <br> " output.innerHTML += "remainder of " + temp + " divided by 3 is: " + intdivby3 + " <br> " }, i * 1000) // <-- changes the duration of the timeout } 
 <div> <input id="seed" type="number" placeholder="seed" value="3"><br> <input id="max" type="number" placeholder="max" value="8"> </div> <button onclick="count()">Count</button> <div id="output"></div> 

Asynchronous while loop ( due to some awesome ES7 stuff (just the newest browsers support it)):

function timer(t){
  return new Promise(r=>setTimeout(r,t));
}

async function main(){
  var a=0;
  while(a<10){
    alert(a);
    a+=1;
    await timer(1000);//wait one second
  }
}
main();

Your code does not work because setTimeout does not stop the current functioj from executing. It will start a timer in the background, and it will then push the passed function onto the so called qeue , wich is executed when the main thread stops.

var a=true;
while(a){
 setTimeout(_=> a=false,1000);
 //will run forever as a is never set to false
}
//the main code would exit here and the timers are somewhen executed
//unreachable point were a=false...

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