如何在JavaScript循环中添加延迟?

我想在while循环中添加一个延迟/睡眠:

我试过这样的:

 alert('hi'); for(var start = 1; start < 10; start++) { setTimeout(function () { alert('hello'); }, 3000); } 

只有第一种情况是正确的:在显示alert('hi') ,它将等待3秒,然后alert('hello')将会显示,但是alert('hello')将会不断地重复。

我希望在alert('hi')后3秒钟显示alert('hello')之后,第二次alert('hello')需要等待3秒钟,等等。

任何人都可以请指教?

setTimeout()函数是非阻塞的,将立即返回。 因此,你的循环将会非常快速地迭代,并且会快速地连续发起3秒超时触发。 这就是为什么你的第一个警报在3秒钟后popup,其余所有的连续不断。

你可能想用这样的东西代替:

 var i = 1; // set your counter to 1 function myLoop () { // create a loop function setTimeout(function () { // call a 3s setTimeout when the loop is called alert('hello'); // your code here i++; // increment the counter if (i < 10) { // if the counter < 10, call the loop function myLoop(); // .. again which will trigger another } // .. setTimeout() }, 3000) } myLoop(); // start the loop 

你也可以通过使用一个自我调用函数来完成它,将迭代的次数作为参数:

 (function myLoop (i) { setTimeout(function () { alert('hello'); // your code here if (--i) myLoop(i); // decrement i and call myLoop again if i > 0 }, 3000) })(10); // pass the number of iterations as an argument 

尝试这样的事情:

 var i = 0, howManyTimes = 10; function f() { alert( "hi" ); i++; if( i < howManyTimes ){ setTimeout( f, 3000 ); } } f(); 

另一种方法是将时间乘以超时,但请注意,这不像睡眠 。 循环后的代码将被立即执行,只有延迟执行callback函数。

 for (var start = 1; start < 10; start++) setTimeout(function () { alert('hello'); }, 3000 * start); 

第一次超时设置为3000 * 1 ,第二次设为3000 * 2等等。

我想你需要这样的东西:

 var TimedQueue = function(defaultDelay){ this.queue = []; this.index = 0; this.defaultDelay = defaultDelay || 3000; }; TimedQueue.prototype = { add: function(fn, delay){ this.queue.push({ fn: fn, delay: delay }); }, run: function(index){ (index || index === 0) && (this.index = index); this.next(); }, next: function(){ var self = this , i = this.index++ , at = this.queue[i] , next = this.queue[this.index] if(!at) return; at.fn(); next && setTimeout(function(){ self.next(); }, next.delay||this.defaultDelay); }, reset: function(){ this.index = 0; } } 

testing代码:

 var now = +new Date(); var x = new TimedQueue(2000); x.add(function(){ console.log('hey'); console.log(+new Date() - now); }); x.add(function(){ console.log('ho'); console.log(+new Date() - now); }, 3000); x.add(function(){ console.log('bye'); console.log(+new Date() - now); }); x.run(); 

注意:使用提醒会阻止JavaScript执行,直到您closures警报。 它可能比你要求的更多的代码,但这是一个强大的可重用的解决scheme。

如果使用ES6,你可以使用let来达到这个目的:

 for (let i=1; i<10; i++) { setTimeout( function timer(){ alert("hello world"); }, i*3000 ); } 

什么let i声明i每个迭代 ,而不是循环。 这样,传递给setTimeout的东西正是我们想要的。

我可能会使用setInteval 。 喜欢这个,

 var period = 1000; // ms var endTime = 10000; // ms var counter = 0; var sleepyAlert = setInterval(function(){ alert('Hello'); if(counter === endTime){ clearInterval(sleepyAlert); } counter += period; }, period); 

在ES6(ECMAScript 2015)中,您可以使用发生器和间隔进行延迟迭代。

发生器是ECMAScript 6的一个新function,可以暂停和恢复。 调用genFunc不会执行它。 相反,它返回一个所谓的生成器对象,让我们控制genFunc的执行。 genFunc()最初在其正文的开头暂停。 genObj.next()方法继续执行genFunc,直到下一个yield。 (探索ES6)

代码示例:

 let arr = [1, 2, 3, 'b']; let genObj = genFunc(); let val = genObj.next(); console.log(val.value); let interval = setInterval(() => { val = genObj.next(); if (val.done) { clearInterval(interval); } else { console.log(val.value); } }, 1000); function* genFunc() { for(let item of arr) { yield item; } } 

这将工作

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

试试这个小提琴: https : //jsfiddle.net/wgdx8zqq/

我用Promise.delay和recursion来做到这一点。

 function myLoop(i) { return Promise.delay(1000) .then(function() { if (i > 0) { alert('hello'); return myLoop(i-=1); } }); } myLoop(3); 
 <script src="ajax/libs/bluebird/2.9.4/bluebird.min.js"></script> 

只是以为我会在这里贴两分钱。 这个函数有一个延迟迭代循环。 看到这个jsfiddle 。 function如下:

 function timeout(range, time, callback){ var i = range[0]; callback(i); Loop(); function Loop(){ setTimeout(function(){ i++; if (i<range[1]){ callback(i); Loop(); } }, time*1000) } } 

例如:

 //This function prints the loop number every second timeout([0, 5], 1, function(i){ console.log(i); }); 

将相当于:

 //This function prints the loop number instantly for (var i = 0; i<5; i++){ console.log(i); } 

您可以使用RxJS 间隔运算符 。 间隔每x秒发射一个整数,并且指定发出次数的次数

 Rx.Observable .interval(1000) .take(10) .subscribe((x) => console.log(x)) 
 <script src="ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script> 

由于ES7是更好的方法来等待循环:

 function timer(ms){ return new Promise(r=>setTimeout(r,ms)); } async function load () { for (var i = 0; i < 3; i++) { console.log(i); await timer(3000); } } load(); 

参考: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

请注意,今天ES7很less得到支持,所以你需要与Babel一起使用才能在任何地方使用它。

Transpiled

  var startIndex = 0; var data = [1, 2, 3]; var timeout = 1000; function functionToRun(i, length) { alert(data[i]); } (function forWithDelay(i, length, fn, delay) { setTimeout(function() { fn(i, length); i++; if (i < length) { forWithDelay(i, length, fn, delay); } }, delay); })(startIndex, data.length, functionToRun, timeout); 

下面是我如何创build一个无限循环的延迟,在一定的条件下打破:

  // Now continuously check the app status until it's completed, // failed or times out. The isFinished() will throw exception if // there is a failure. while (true) { let status = await this.api.getStatus(appId); if (isFinished(status)) { break; } else { // Delay before running the next loop iteration: await new Promise(resolve => setTimeout(resolve, 3000)); } } 

这里的关键是创build一个新的承诺,超时解决,并等待解决。

显然你需要asynchronous/等待支持。 在节点8中工作。

 /* Use Recursive and setTimeout call below function will run loop loopFunctionNeedCheck until conditionCheckAfterRunFn = true, if conditionCheckAfterRunFn == false : delay reRunAfterMs miliseconds and continue loop tested code, thanks */ function functionRepeatUntilConditionTrue(reRunAfterMs, conditionCheckAfterRunFn, loopFunctionNeedCheck) { loopFunctionNeedCheck(); var result = conditionCheckAfterRunFn(); //check after run if (!result) { setTimeout(function () { functionRepeatUntilConditionTrue(reRunAfterMs, conditionCheckAfterRunFn, loopFunctionNeedCheck) }, reRunAfterMs); } else console.log("completed, thanks"); //if you need call a function after completed add code call callback in here } //passing-parameters-to-a-callback-function // From Prototype.js if (!Function.prototype.bind) { // check if native implementation available Function.prototype.bind = function () { var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift(); return function () { return fn.apply(object, args.concat(Array.prototype.slice.call(arguments))); }; }; } //test code: var result = 0; console.log("---> init result is " + result); var functionNeedRun = function (step) { result+=step; console.log("current result is " + result); } var checkResultFunction = function () { return result==100; } //call this function will run loop functionNeedRun and delay 500 miliseconds until result=100 functionRepeatUntilConditionTrue(500, checkResultFunction , functionNeedRun.bind(null, 5)); //result log from console: /* ---> init result is 0 current result is 5 undefined current result is 10 current result is 15 current result is 20 current result is 25 current result is 30 current result is 35 current result is 40 current result is 45 current result is 50 current result is 55 current result is 60 current result is 65 current result is 70 current result is 75 current result is 80 current result is 85 current result is 90 current result is 95 current result is 100 completed, thanks */ 

这是一个我用来循环数组的函数:

 function loopOnArrayWithDelay(theArray, delayAmount, i, theFunction, onComplete){ if (i < theArray.length && typeof delayAmount == 'number'){ console.log("i "+i); theFunction(theArray[i], i); setTimeout(function(){ loopOnArrayWithDelay(theArray, delayAmount, (i+1), theFunction, onComplete)}, delayAmount); }else{ onComplete(i); } } 

你这样使用它:

 loopOnArrayWithDelay(YourArray, 1000, 0, function(e, i){ //Do something with item }, function(i){ //Do something once loop has completed } 

这个脚本适用于大多数事情

 function timer(start) { setTimeout(function () { //The timer alert('hello'); }, start*3000); //needs the "start*" or else all the timers will run at 3000ms } for(var start = 1; start < 10; start++) { timer(start); } 

尝试这个

 //the code will execute in 1 3 5 7 9 seconds later function exec(){ for(var i=0;i<5;i++){ setTimeout(function(){ console.log(new Date()); //It's you code },(i+i+1)*1000); } }