JavaScript:For循环超时

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

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

我发现像这样的堆溢出许多解决scheme:

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

但是在所有的实现中,循环最初等待3000,然后一次执行整个循环。 是否有一种方法,每个迭代在等待1000之后被调用。

你可以用简单的math来解决这个问题:

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

1000ms:0
4000ms:1
7000毫秒: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); } 

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

 (function fn(n) { console.log(n); if (n < 9) setTimeout(function() { fn(++n); }, 1000); }(0)); 

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

 var i = 0 var id = window.setInterval(function(){ if(i >= 10) { clearInterval(id); return; } console.log(i); i++; }, 1000) 

这工作:

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

这样你只会在你的函数执行的时候递增,我相信这是你的要求。

小提琴中的示例: 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); 
 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 

工作演示

你可以用两种方式来处理你的情况。

  1. 你可以直接安排一大堆setTimeout()调用,这些调用会在不同的时间进行,所以它们将会在将来的所需时间执行(这里的其他答案说明了如何做)。

  2. 您可以执行第一次迭代,计划下一次迭代,然后执行下一次迭代计划,直到完成所需的迭代次数。 这比设置大量setTimeout()调用最终更具可扩展性,并为您提供更多的分支/逻辑自由度,因为您可以控制每次迭代之后发生的情况。

使用更通用的实用程序函数的第二个选项如下所示:

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

这也可以用迭代完成时调用的第二个callback函数进行扩展(在某些情况下很有用),或者可以返回在迭代完成时parsing的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"); }); 

这是一个简单的超时解决scheme…也许它不符合你的期望,但试图让一个“暂停”的JavaScript是不是一个好方法在我的build议。 我build议你search另一种方式来做你想做的事情。 小提琴

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

@ Karl-AndréGagnon的回答非常好,除了OP不需要初始等待时间,所以在第一次迭代中我们除以零:

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

这里的大部分答案都是完全错误的。

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

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

这里是解决scheme:

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

这是一个es6解决scheme。 我真的不喜欢在函数中包装setTimeout ,当你可以简单地使用一个块范围的variables,如下所示:

 for (let i=0; i<=10; i++) { setTimeout(() => {console.log(i);}, 1000 * i); }