JavaScript中带循环的setTimeout

JavaScript中带循环的setTimeout,javascript,Javascript,我有一个非常琐碎的问题。对于带有setTimeout的简单循环,如下所示: for (var count = 0; count < 3; count++) { setTimeout(function() { alert("Count = " + count); }, 1000 * count); } Count = 3 Count = 3 Count = 3 //first iteration var count = 0; //this is 1 bec

我有一个非常琐碎的问题。对于带有setTimeout的简单循环,如下所示:

for (var count = 0; count < 3; count++) {
    setTimeout(function() {
        alert("Count = " + count);
    }, 1000 * count);
}
Count = 3
Count = 3
Count = 3
//first iteration
var count = 0; //this is 1 because of count++ in your for loop.

for (count = 0; count < 3; count++) { 
    setTimeout(function() {
        alert("Count = " + 1);
    }, 1000 * 1);
}
count = count + 1; //count = 1

//second iteration
var count = 1;

for (count = 0; count < 3; count++) {
    setTimeout(function() {
        alert("Count = " + 2);
    }, 1000 * 2);
}
count = count + 1; //count = 2

//third iteration
var count = 2;

for (count = 0; count < 3; count++) {
    setTimeout(function() {
        alert("Count = " + 3);
    }, 1000 * 3);
}
count = count + 1; //count = 3

//after 1000 ms
window.setTimeout(alert(count));
//after 2000 ms
window.setTimeout(alert(count));
//after 3000 ms
window.setTimeout(alert(count));
不知道为什么输出是这样的。任何人都可以解释,请考虑一下:

  • 代码执行一个循环,在该循环中它设置一些代码以供以后运行
  • 循环结束
  • 执行setTimeout代码。
    count
    的值是多少?循环在几年前完成
    这与闭包范围有关。每个setTimeout回调函数的作用域中都有相同的变量
    count
    。您正在增加它的值并创建一个函数,但函数的每个实例在其作用域中都有相同的变量
    count
    ,在回调函数执行时,它的值将为3

    您需要在
    for
    循环中的新作用域内创建变量的副本(例如
    var localCount=count
    ),以使其正常工作。由于
    for
    没有创建作用域(这是整个事件的原因),因此需要引入一个带有函数作用域的作用域

    e、 g

    for(变量i=0;i<5;i++){
    (功能(){
    var j=i;
    setTimeout(函数(){
    控制台日志(j)
    },
    j*100);
    })();
    }
    
    这与JavaScript如何处理作用域和提升有关

    代码中发生的情况是JS引擎将代码修改为:

    var count;
    
    for (count = 0; count < 3; count++) {
        setTimeout(function() {
            alert("Count = " + count);
        }, 1000 * count);
    }
    

    这是因为所有超时都是在循环完成时运行的

    然后,超时函数取当前值count


    这总是3,因为for循环已经完成。

    这是因为在for循环完成执行时,计数是3,然后调用设置的超时

    试试这个:

    var count = 0; 
    setTimeout(function() {
           for (count = 0; count < 3; count++) {
               alert("Count = " + count);
            }
    }, 1000* count);
    
    var计数=0;
    setTimeout(函数(){
    用于(计数=0;计数<3;计数++){
    警报(“计数=”+计数);
    }
    },1000*计数);
    
    这样想:

    1000*n毫秒结束后,计数的值是多少

    当然是3,因为foor循环的结束时间早于1000*n ms的超时时间

    要打印1,2,3,您需要以下内容:

    for (var count = 0; count < 3; count++) {
        do_alert(num);
    }
    
    function do_alert(num) {
        setTimeout(function() {
            alert("Count = " + num);
        }, 1000 * num);
    }
    
    function timedAlert(n) {
      if (n < 3) {
        setTimeout(function() {
            alert("Count = " + n);
            timedAlert(++n);
        }, 1000);
      }
    }
    
    timedAlert(0);
    
    这两个代码示例实际上工作方式类似

    第一个示例在每次迭代中调用一个命名函数(do_alert)

    第二个示例在每次迭代中调用闭包匿名函数(类似于
    do\u alert

    这都是范围问题


    希望有帮助。

    更好的解决方案是“忘记循环和递归”在这种情况下,使用“setInterval”的组合包括“setTimeOut”:

    函数iAsk(lvl){
    var i=0;
    var intr=setInterval(函数(){//启动循环
    i++;//递增它
    如果(i>lvl){//检查是否达到结束轮。
    清除间隔(intr);
    返回;
    }
    setTimeout(函数(){
    $(“.imag”).prop(“src”,pPng);//在50毫秒后执行第一个bla bla bla bla bla bla
    },50);
    setTimeout(函数(){
    //100毫秒后再做一次布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉布拉。
    seq[i-1]=(Math.ceil(Math.random()*4)).toString();
    $(“#hh”).after('
    '+i+':rand='+(Math.ceil(Math.random()*4)).toString()+'>'+seq[i-1]); 美元(“#d”+序号[i-1])。道具(“src”,pGif); var d=document.getElementById('aud'); d、 play(); },100); setTimeout(函数(){ //继续添加bla bla bla bla,直到完成:) 美元(“#d”+序号[i-1])。道具(“src”,pPng); },900); },1000);//循环等待时间必须大于等于900(内部操作的最大超时) }
    PS:了解(setTimeOut)的真实行为:它们都将在同一时间开始“三个bla bla bla将在同一时刻开始倒计时”,因此,请设置不同的超时来安排执行


    PS 2:计时循环的示例,但对于反应循环,您可以使用事件,promise async await..

    这里简单的解决方法是使用es6
    let
    局部变量。您的代码看起来几乎相同,只是它能实现您的期望:)

    for(让count=0;count<3;count++){
    setTimeout(函数(){
    警报(“计数=”+计数);
    },1000*计数);
    }
    
    或者您可以创建一个递归函数来完成该工作,如下所示:

    for (var count = 0; count < 3; count++) {
        do_alert(num);
    }
    
    function do_alert(num) {
        setTimeout(function() {
            alert("Count = " + num);
        }, 1000 * num);
    }
    
    function timedAlert(n) {
      if (n < 3) {
        setTimeout(function() {
            alert("Count = " + n);
            timedAlert(++n);
        }, 1000);
      }
    }
    
    timedAlert(0);
    
    函数timedAlert(n){
    if(n<3){
    setTimeout(函数(){
    警报(“计数=”+n);
    timedAlert(++n);
    }, 1000);
    }
    }
    timedAlert(0);
    
    首先,setTimeout(函数,毫秒)是一个在“毫秒”毫秒后执行函数的函数

    请记住,JS将函数视为对象,因此for(…)循环最初将生成如下内容:

    setTimeout(…)
    设置超时(…)
    设置超时(…)
    

    现在setTimeout()函数将逐个执行

    函数的作用是:在当前范围内查找count变量。否则,它将转到外部作用域并找到count,其值已由for循环增加到3


    现在,开始执行…第一个警报立即显示,因为毫秒为0,第二个警报在1000毫秒后显示,然后第三个警报在2000毫秒后显示。所有这些警报都显示
    Count=3

    的可能重复项不起作用:
    for(var i=0;i<5;i++){var j=i;setTimeout(function(){console.log(j)},j*100);}
    这是因为'j'变量被提升到父作用域中,因为for循环没有创建父作用域。您需要创建一个新的函数作用域来隔离
    j
    for(var i=0;i<5;i++){(function(){var j=i;setTimeout(function(){console.log(j)},j*100);}()}}
    那么为什么在使用iLife时要创建副本呢?你可以就这么做
     for (let count = 0; count < 3; count++) {
        setTimeout(function() {
            alert("Count = " + count);
        }, 1000 * count);
    
    }
    
    function timedAlert(n) {
      if (n < 3) {
        setTimeout(function() {
            alert("Count = " + n);
            timedAlert(++n);
        }, 1000);
      }
    }
    
    timedAlert(0);