在While循环中setTimeout不起作用

时间:2017-06-11 16:24:26

标签: javascript while-loop settimeout

我11岁,刚刚开始编程。我试图使用while循环,我希望它以块为单位显示答案而不是一个巨大的块。所以我试着使用一个setTimeout,但它会在一秒钟之后显示第一行,然后立即将其余部分显示为一个巨大的块。然后它会使用数字9作为临时变量,即使我不知道它来自哪里。谢谢提前。

我想在代码中保留while循环,因为我正在学习如何使用它们,所以如果你能在你的答案中保留while语句就太棒了!

这是我的代码:

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

3 个答案:

答案 0 :(得分:2)

将循环与超时混合是一个坏主意,而是使用间隔并在条件不再为真时将其删除

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

小例子

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

另一种方法是使用递归超时

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

小例子

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

答案 1 :(得分:2)

我看到你在那里尝试做什么,但遗憾的是它不会像你想的那样发挥作用。

setTimeout()不会暂停其余的代码,它只是说“在运行我内部的东西之前等待这段时间”,同时脚本的其余部分将继续保持稳定。因此,在循环的每个步骤之间没有一秒钟的延迟,你的循环会一个接一个地遍历整个集合,然后一秒钟之后所有的setTimeouts都会一个接一个地触发。

javascript中一种更典型的方式来做你想做的事情(导致一大块代码在每次重复之间反复运行)setInterval() - 它的工作方式几乎与setTimeout()完全相同,除了它会在每次间隔到期时继续发射(直到你用clearInterval()取消它。)例如:

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>

但是,正如练习一样,可以通过在循环中逐步更改每个setTimeout的持续时间来组合whilesetTimeout - 这样您就可以启动所有setTimeouts同时(几乎),但增加每个人在发生之前等待的时间。

但是有一个问题:你需要每个setTimeout为temp使用不同的值。如果你尝试在一个函数中处理这一切,那么在第一个setTimeout触发时,while循环已经将变量一直递增到循环中,所以每个setTimeout最终都使用了本来应该是最后一次迭代的值。 。 (你的代码也有同样的问题:这就是你在第一次迭代中看到'9'的原因。)

如果你试图通过等待增加变量直到setTimeout内部来解决这个问题,你只需要一个无限循环,因为第一个增量不会发生,直到第一个setTimeout触发。所以这也不好。 (无休止循环通常是在使用while时发生的情况,这就是我在几乎任何情况下都避免使用它的原因。)

您可以通过调用具有每次迭代所需的特定值的第二个函数来解决此问题,并让该辅助函数使用自己的持续时间设置自己的超时:

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>

答案 2 :(得分:0)

异步while循环(由于一些很棒的ES7内容(只是最新的浏览器支持它)):

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

您的代码不起作用,因为setTimeout不会停止执行当前的functioj。它将在后台启动一个计时器,然后将传递的函数推送到所谓的 qeue ,当主线程停止时执行。

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