JavaScript:用于超时的循环

时间:2014-06-18 19:12:57

标签: javascript settimeout

我希望我的for循环不应该立即执行,而是在每次迭代后等待超时。例如:

for(var i=0; i<10; i++) {
    console.log(i);
    //wait for 1000
}

我发现堆栈溢出的许多解决方案都像这样:

for (var i=0;i<=10;i++) {
   (function(ind) {
       setTimeout(function(){console.log(ind);}, 3000);
   })(i);
}

但是在所有实现中,循环最初等待3000毫秒,然后立即执行整个for循环。有没有办法在等待1000毫秒后调用每个迭代。

12 个答案:

答案 0 :(得分:30)

你可以用简单的数学方法解决这个问题:

for (var i=0;i<=10;i++) {
   (function(ind) {
       setTimeout(function(){console.log(ind);}, 1000 + (3000 * ind));
   })(i);
}
  

1000ms:0
  4000ms:1
  7000ms:2
  10000ms:3
  13000ms:4
  ...


发表评论

您的请求似乎有点模糊。如果您想在上次超时后执行某些操作,可以设置限制并比较当前索引:

var limit = 10
for (var i=0;i<=limit;i++) {
   (function(ind) {
       setTimeout(function(){
           console.log(ind);
           if(ind === limit){
               console.log('It was the last one');
           }
       }, 1000 + (3000 * ind));
   })(i);
}

小提琴:http://jsfiddle.net/Tn4A7/


我想我知道你想要什么...

只是做

for (var i=0;i<=10;i++) {
   (function(ind) {
       setTimeout(function(){console.log(ind);}, 1000 * ind);
   })(i);
}

答案 1 :(得分:13)

不要在循环中创建函数,而是:

&#13;
&#13;
(function fiveSeconds  (n) {

  if (n < 5) setTimeout(function () {  
    fiveSeconds ( n ); // Redo if n < 5 (and pass n)
  }, 1000);
  
  console.log( n++ );

} (0)); // Initialize. n is 0
&#13;
&#13;
&#13;

以上将以1 - 5秒的间隔从0 - 5记录十个数字

现代浏览器(和IE10 +)

&#13;
&#13;
(function fiveSeconds (n) {

  console.log( n++ );

  if (n <= 5) setTimeout( fiveSeconds, 1000, n ); // Redo if n <= 5 (and pass n)
  
} (0)); // Initialize. n is 0
&#13;
&#13;
&#13;

答案 2 :(得分:6)

为什么不使用这样的东西:

var i = 0
var id = window.setInterval(function(){
    if(i >= 10) {
        clearInterval(id);
        return;
    }

    console.log(i);
    i++;
}, 1000)

答案 3 :(得分:3)

这有效:

function initiateTimeOut(i) {
  setTimeout(function() { doStuff(i) }, 30);
}
function doStuff(i) {
    console.log(i);
    i++;
    if (i <= 10) {
        initiateTimeOut(i); 
    }
}

initiateTimeOut(0);

这样你只会在你的功能执行时递增i,我相信这就是你要找的东西。

小提琴中的示例: http://jsfiddle.net/My7Zg/


或者,甚至更短( http://jsfiddle.net/My7Zg/1/ ):

function customLoop(i) {
    console.log(i);
    i++;
    if (i<=10) {setTimeout(function(){customLoop(i);},1000);}
}
customLoop(0);

答案 4 :(得分:1)

for (var i=0;i<=10;i++) {
   (function(ind) {
       setTimeout(function(){console.log((ind + 1)*1000, ':', ind);}, 1000 * (ind+1) );
   })(i);
}

输出:

1000 : 0
2000 : 1
3000 : 2
4000 : 3
5000 : 4
6000 : 5
7000 : 6
8000 : 7
9000 : 8
10000 : 9
11000 : 10

WORKING DEMO

答案 5 :(得分:1)

您可以通过两种方式处理您的情况。

  1. 您可以随时安排一大堆setTimeout()次呼叫,以便将来在所需的时间执行(此处的其他答案说明了如何执行此操作)。

    < / LI>
  2. 您可以执行第一次迭代,安排下一次迭代并执行下一次迭代计划,然后完成所需的迭代次数。这最终比设置大量setTimeout()调用更具可伸缩性,并为您提供更多的分支/逻辑自由,因为您可以控制每次迭代后接下来发生的事情。

  3. 使用更通用的实用程序功能的第二个选项如下所示:

    // utility function to call a callback numTimes, 
    // separated by delay milliseconds
    function runIteration(fn, numTimes, delay) {
        var cnt = 0;
        function next() {
            // call the callback and stop iterating if it returns false
            if (fn(cnt) === false) return;
            ++cnt;
            // if not finished with desired number of iterations,
            // schedule the next iteration
            if (cnt < numTimes) {
                setTimeout(next, delay);
            }
        }
        // start first iteration
        next();
    
    }
    

    因此,要执行您的控制台声明,您可以这样做:

    runIteration(function(i) {
        console.log(i);
    }, 10, 1000);
    

    工作演示:http://jsfiddle.net/jfriend00/HqCZ3/

    这也可以通过第二个回调函数进行扩展,该函数在迭代完成时调用(在某些情况下很有用),或者它可以返回在迭代完成时解析的promise。

    以下是返回承诺的版本:http://jsfiddle.net/jfriend00/XtJ69/

    // utility function to call a callback numTimes, 
    // separated by delay milliseconds
    function runIteration(fn, numTimes, delay) {
        var d = $.Deferred();
        var cnt = 0;
    
        function end() {
            d.resolve();
        }
    
        function next() {
            // call the callback and stop iterating if
            // it returns false
            if (fn(cnt) === false) {
                end();
                return;
            }
            ++cnt;
            // if not finished with desired number of iterations,
            // schedule the next iteration
            if (cnt < numTimes) {
                setTimeout(next, delay);
            } else {
                end();
            }
        }
        // start first iteration
        next();
        return d.promise();
    }
    
    
    runIteration(function(i) {
        log(i);
    }, 10, 1000).done(function() {
        log("done");
    });
    

答案 6 :(得分:0)

这是一个简单超时的解决方案......也许它与你的期望不完全匹配,但试图做出一个&#34;暂停&#34;用javascript在我的建议中不是一个好方法。我建议你用另一种方式去做你想做的事。 Fiddle

window.my_condition = true;
window.my_i = 0;

function interate() {
    console.log(window.my_i);
    // ... your code
    if (window.my_condition!==false) {
        window.my_i++;
        setTimeout(interate,300);
    }
}

interate();

答案 7 :(得分:0)

这里的大多数答案都是完全错误的。

如果你想等待每次迭代完成---那么你不想使用for循环 - 只是错误的策略开始。

你需要使用计数器和计数器限制,否则它将无休止地循环。

这是解决方案:

var optionLimit = 11;
var optionItem = 1;
function do_something_else() {
    if (optionItem < optionLimit) {
        console.log('doing stuff:' + optionItem)
        optionItem++
        dostuff();
    } else {
        console.log('no more stuff to do already reached:' + optionItem)
    }
}
function dostuff(started) {
    if (started) {
        console.log('started doing something');
    } else {
        console.log('find something else to do');
    }
    setTimeout(function () {
        do_something_else();
    }, 3000);
}
dostuff('started doing something');

如果您有一组需要索引的项目 - 那么您可以使用循环来计算需要执行的项目数量,如下所示:

var thingstodo = [
    thing1 = {
        what: 'clean room',
        time: 8000
    },
    thing2 = {
        what: 'laundry',
        time: 9000
    },
    thing3 = {
        what: 'take out trash',
        time: 6000
    },
    thing4 = {
        what: 'wash dishes',
        time: 10000
    }
]
var optionLimit = 0;
// find how many things to do from things to do list
function get_things_todo(time) {
    console.log('heres stuff i can do');
    console.log('====================');
    for (var i = 0; i < thingstodo.length; i++) {
        val = thingstodo[i];
        console.log(JSON.stringify(val.what));
        optionLimit++
    }
    setTimeout(function () {
        startdostuff(3000)
    }, time);
}
var optionItem = 0;
// find the next thing to do on the list
function get_next_thing(time) {
    setTimeout(function () {
        console.log('================================');
        console.log('let me find the next thing to do');
    }, time);
    setTimeout(function () {
        if (optionItem < optionLimit) {            
            val = thingstodo[optionItem];            
            dostuff(3000, val);
            optionItem++
        } else {
            console.log('=====================================================');
            console.log('no more stuff to do i finished everything on the list')
        }
    }, time*1.5);
}
//do stuff with a 3000ms delay
function dostuff(ftime, val) {
    setTimeout(function () {
        console.log('================================');
        console.log('im gonna ' + JSON.stringify(val.what));
        console.log('will finish in: ' + JSON.stringify(val.time) + ' milliseconds');
        setTimeout(function () {
            console.log('========');
            console.log('all done');
            get_next_thing(3000);
        }, val.time);
    }, ftime);
}
//start doing stuff
function startdostuff(time) {
    console.log('========================');
    console.log('just started doing stuff');
    setTimeout(function () {
        get_next_thing(3000);
    }, time);
}
/// get things to first
get_things_todo(3000);

答案 8 :(得分:0)

这是一个var x = document.referrer; if (x == "page2.html") { console.log(x); } else { window.location.href = "login.html"; }; 解决方案。我真的不喜欢在函数中包装es6,只需使用这样的块作用域变量:

setTimeout

答案 9 :(得分:0)

我最好的工作方式是忘记正常循环&#34;在这种情况下,使用&#34; setInterval&#34;包括&#34; setTimeOut&#34; s:

    function iAsk(lvl){
        var i=0;
        var intr =setInterval(function(){ // start the loop 
            i++; // increment it
            if(i>lvl){ // check if the end round reached.
                clearInterval(intr);
                return;
            }
            setTimeout(function(){
                $(".imag").prop("src",pPng); // do first bla bla bla after 50 millisecond
            },50);
            setTimeout(function(){
                 // do another bla bla bla after 100 millisecond.
                seq[i-1]=(Math.ceil(Math.random()*4)).toString();
                $("#hh").after('<br>'+i + ' : rand= '+(Math.ceil(Math.random()*4)).toString()+' > '+seq[i-1]);
                $("#d"+seq[i-1]).prop("src",pGif);
                var d =document.getElementById('aud');
                d.play();                   
            },100);
            setTimeout(function(){
                // keep adding bla bla bla till you done :)
                $("#d"+seq[i-1]).prop("src",pPng);
            },900);
        },1000); // loop waiting time must be >= 900 (biggest timeOut for inside actions)
    }
PS:理解(setTimeOut)的真实行为:它们都将在同一时间开始&#34;三个bla bla bla将在同一时刻开始倒计时#34;所以要做一个不同的超时来安排执行。

PS 2:定时循环的示例,但对于反应循环,您可以使用事件,承诺异步等待..

答案 10 :(得分:0)

我分享了一个简单的解决方案。

要解决这个问题,您需要使用闭包:立即调用将在每次迭代中调用的函数,并在此函数内以“i”作为参数和 setTimeout。在这种情况下,您传递的参数将存储在作用域中并可用于超时回调:

for (var i=1; i<6; i++) (function(t) {
    setTimeout(function() {
    //do anything with t
    }, t*1000)
}(i))

通过此示例,您将大致了解该函数会发生什么:

for (var i=1; i<6; i++) (function(t) {
    setTimeout(function() {
    console.log(t);
    }, t*1000)
}(i))

答案 11 :(得分:0)

另一种解决方法是将 generator functionsetInterval 一起使用:

const steps = function*() {
  for (let i=0; i<10; i++) {
    yield i;
  }
}

const step = steps();
setInterval(function(){ 
    console.log(step.next().value)
}, 1000);