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

时间:2010-08-27 11:36:10

标签: javascript loops sleep

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

我试过这样:

alert('hi');

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

只有第一种情况属实:显示alert('hi')后,它会等待3秒钟,然后会显示alert('hello'),但alert('hello')会不断重复。

我想要的是alert('hello')alert('hi')后3秒显示,然后需要等待3秒,第二次alert('hello'),依此类推。

35 个答案:

答案 0 :(得分:656)

setTimeout()功能是非阻塞功能,将立即返回。因此,您的循环将非常快速地迭代,并且将快速连续地一个接一个地启动3秒超时触发。这就是为什么你的第一个警报会在3秒后弹出,其余所有警报都会连续不断地跟随。

你可能想要使用这样的东西:

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

答案 1 :(得分:60)

尝试这样的事情:

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

答案 2 :(得分:48)

如果使用ES6,您可以使用let来实现此目的:

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

let为每个迭代声明i,而不是循环。这样,传递给setTimeout的内容正是我们想要的。

答案 3 :(得分:23)

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

function timer(ms) {
 return new Promise(res => setTimeout(res, ms));
}

async function load () {
  for (var i = 0; i < 3; i++) {
    console.log(i);
    await timer(3000);
  }
}

load();

Reference on MDN

请注意,今天很少支持ES7,因此您需要与Babel进行交互以便在任何地方使用它。

Transpiled

答案 4 :(得分:21)

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

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

第一次超时将设为3000 * 1,第二次设为3000 * 2,依此类推。

答案 5 :(得分:15)

我认为你需要这样的东西:

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

测试代码:

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执行,直到您关闭警报。 它可能比您要求的代码更多,但这是一个强大的可重用解决方案。

答案 6 :(得分:14)

我可能会使用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);

答案 7 :(得分:12)

这将有效

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

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

答案 8 :(得分:7)

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

  

生成器,ECMAScript 6的一个新功能,是可以的功能   暂停并恢复。调用genFunc不会执行它。相反,它   返回一个所谓的生成器对象,让我们控制genFunc   执行。 genFunc()最初在其开头被暂停   身体。 genObj.next()方法继续执行genFunc,   直到下一个收益率。   (Exploring ES6)


代码示例:

&#13;
&#13;
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;
  }
}
&#13;
&#13;
&#13;

所以,如果你使用的是ES6,这是实现延迟循环的最优雅方式(我认为)。

答案 9 :(得分:4)

我使用Bluebird的Promise.delay和递归。

&#13;
&#13;
function myLoop(i) {
  return Promise.delay(1000)
    .then(function() {
      if (i > 0) {
        alert('hello');
        return myLoop(i -= 1);
      }
    });
}

myLoop(3);
&#13;
<script src="//cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.4/bluebird.min.js"></script>
&#13;
&#13;
&#13;

答案 10 :(得分:4)

在ES6中,您可以执行以下操作:

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

在ES5中,您可以执行以下操作:

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

原因是,let允许您声明限于block语句或使用该语句的表达式的变量,而不像var关键字那样全局定义变量,或者在整个函数中本地使用,而不管块范围如何。

答案 11 :(得分:3)

我以为我也会在这里发两分钱。此函数运行具有延迟的迭代循环。见this jsfiddle。功能如下:

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

答案 12 :(得分:3)

您可以使用RxJS interval operator。 Interval每x秒发出一次整数,take指定它必须发出数字的次数

&#13;
&#13;
Rx.Observable
  .interval(1000)
  .take(10)
  .subscribe((x) => console.log(x))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script>
&#13;
&#13;
&#13;

答案 13 :(得分:2)

无功能的解决方案

聚会有点晚了,但是有一个不用任何函数的解决方案:

alert('hi');

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

答案 14 :(得分:1)

&#13;
&#13;
    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);
&#13;
&#13;
&#13;

Daniel Vassallo的修改版本的答案,将变量提取到参数中以使函数更具可重用性:

首先让我们定义一些基本变量:

var startIndex = 0;
var data = [1, 2, 3];
var timeout = 3000;

接下来,您应该定义要运行的功能。这将通过i,循环的当前索引和循环的长度,以备不时之需:

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

功能版

function forWithDelay(i, length, fn, delay) {
   setTimeout(function () {
      fn(i, length);
      i++;
      if (i < length) {
         forWithDelay(i, length, fn, delay); 
      }
  }, delay);
}

forWithDelay(startIndex, data.length, functionToRun, timeout); // Lets run it

答案 15 :(得分:1)

只需尝试

 var arr = ['A','B','C'];
 (function customLoop (arr, i) {
    setTimeout(function () {
    // Do here what you want to do.......
    console.log(arr[i]);
    if (--i) {                
      customLoop(arr, i); 
    }
  }, 2000);
})(arr, arr.length);

结果

A // after 2s
B // after 2s
C // after 2s

答案 16 :(得分:1)

除了10年前公认的答案外,使用更现代的Javascript,人们还可以使用async / await / Promise()或生成器函数来实现正确行为。 (其他答案中建议的错误行为是设置一系列3秒警报,而不考虑“接受” alert()-还是完成手头的任务)

使用async / await / Promise()

alert('hi');

(async () => {
  for(let start = 1; start < 10; start++) {
    await new Promise(resolve => setTimeout(() => {
      alert('hello');
      resolve();
    }, 3000));
  }
})();

使用生成器功能:

alert('hi');

let func;

(func = (function*() {
  for(let start = 1; start < 10; start++) {
    yield setTimeout(() => {
      alert('hello');
      func.next();
    }, 3000);
  }
})()).next();

答案 17 :(得分:0)

您这样做:

console.log('hi')
let start = 1
setTimeout(function(){
  let interval = setInterval(function(){
    if(start == 10) clearInterval(interval)
    start++
    console.log('hello')
  }, 3000)
}, 3000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

答案 18 :(得分:0)

   let counter =1;
   for(let item in items) {
        counter++;
        setTimeout(()=>{
          //your code
        },counter*5000); //5Sec delay between each iteration
    }

答案 19 :(得分:0)

var count = 0;

//Parameters:
//  array: []
//  fnc: function (the business logic in form of function-,what you want to execute)
//  delay: milisecond  

function delayLoop(array,fnc,delay){
    if(!array || array.legth == 0)return false;
    setTimeout(function(data){ 
        var data = array[count++];
        fnc && fnc(data);
        //recursion...
        if(count < array.length)
            delayLoop(array,fnc,delay);
        else count = 0;     
    },delay);
}

答案 20 :(得分:0)

function waitforme(ms)  {

return new Promise( resolve => {

    setTimeout(()=> {resolve('')} ,ms );


})


}



async function printy()  {




for (let i= 0; i < 10 ; ++i)    {


    await waitforme(1000);
    //wait for 500 milisecond

    console.log(i);


}


console.log("I Ran after the loop finished :)");
}


printy();

答案 21 :(得分:0)

我认为,在循环中添加延迟的最简单,最优雅的方法是这样的:

names = ['John', 'Ana', 'Mary'];

names.forEach((name, i) => {
 setTimeout(() => {
  console.log(name);
 }, i * 1000);  // one sec interval
});

答案 22 :(得分:0)

const autoPlayer = (arr = [1, 2, 3, 4, 5]) => {
  // Base case:
  if (arr.length < 1) return

  // Remove the first element from the array.
  const item = arr.shift()

  // Set timout 
  setTimeout(() => {
    console.log('Hello, world!', item)  // Visualisation.
    autoPlayer() // Call function again.
  }, 1000) // Iterate every second.
}

嘿,我知道这篇文章很旧,但是这段代码“循环”并使用递归方法为其添加了延迟。我认为您不能“实际上”根据阅读其他人的各种评论来延迟循环本身的迭代。也许这可以帮助某人!基本上该函数接受一个数组(在本例中)。在每次迭代时,都会调用 setTimeout Javascript 方法。当 setTimeout 函数的计时器到期时,该函数再次无限期地调用自身,但每次调用时,数组都会变小,直到达到基本情况。我希望这可以帮助其他人。

答案 23 :(得分:0)

var loop=(i,time)=>new Promise(r=>{
 alert("aaa",i);
 if(i>0)
 setTimeout(()=>{
    r([i-1,time]);
 },time);
}).then(v=>loop(v[0],v[1]))

loop(3,1000);

试试

答案 24 :(得分:0)

据我所知setTimeout函数是异步调用的。您可以做的是将整个循环包装在async函数中,然后等待包含setTimeout的Promise,如下所示:

var looper = async function () {
  for (var start = 1; start < 10; start++) {
    await new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log("iteration: " + start.toString());
        resolve(true);
      }, 1000);
    });
  }
  return true;
}

然后您像这样调用它:

looper().then(function(){
  console.log("DONE!")
});

请花一些时间来更好地理解异步编程。

答案 25 :(得分:0)

简单的实现,只要循环正在运行,每两秒钟就会显示一段文本。

for (var i = 0; i < foo.length; i++) {
   setInterval(function(){ 
     console.log("I will appear every 2 seconds"); 
   }, 2000);
  break;
};

答案 26 :(得分:0)

<!DOCTYPE html>
<html>
<body>

<button onclick="myFunction()">Try it</button>

<p id="demo"></p>

<script>
function myFunction() {
    for(var i=0; i<5; i++) {
    	var sno = i+1;
       	(function myLoop (i) {          
             setTimeout(function () {   
             	alert(i); // Do your function here 
             }, 1000*i);
        })(sno);
    }
}
</script>

</body>
</html>

答案 27 :(得分:0)

常用&#34;忘记正常循环&#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:定时循环的示例,但对于反应循环,您可以使用事件,承诺异步等待..

答案 28 :(得分:0)

以下是我如何创建一个具有在某种条件下中断的延迟的无限循环:

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

这里的关键是创建一个新的Promise,它可以通过超时解析,并等待其解析。

显然你需要async / await支持。在节点8中工作。

答案 29 :(得分:0)

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

答案 30 :(得分:-1)

试试这个......

var icount=0;
for (let i in items) {
   icount=icount+1000;
   new beginCount(items[i],icount);
}

function beginCount(item,icount){
  setTimeout(function () {

   new actualFunction(item,icount);

 }, icount);
}

function actualFunction(item,icount){
  //...runs ever 1 second
 console.log(icount);
}

答案 31 :(得分:-1)

var timer, i = 10;
function myLoop () { //  create a loop function
  timer = setTimeout(function () {   
    document.getElementById("demo").innerHTML = i;
   
    i--;                    
    if (i >= 0) {            
      myLoop();              
    } else {               
      clearTimeout(timer); // clear timeout
      document.getElementById("demo").innerHTML = "DOARRRR ..";
    }
   
  }, 1000);
}

myLoop();
<p id="demo">count</p>

答案 32 :(得分:-1)

此脚本适用于大多数事情

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

答案 33 :(得分:-1)

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

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
}

答案 34 :(得分:-2)

试试这个

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