Я хотел бы добавить задержку / сон внутри цикла while:

Пробовал вот так:

alert('hi');

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

Только первый сценарий верен: после показа alert('hi') он будет ждать 3 секунды, затем будет отображаться alert('hello'), но затем alert('hello') будет повторяться постоянно.

Я хотел бы, чтобы после alert('hello') отображалось 3 секунды после alert('hi'), затем ему нужно подождать 3 секунды во второй раз alert('hello') и так далее.

386
olidev 27 Авг 2010 в 15:36

26 ответов

Лучший ответ

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
727
Daniel Vassallo 27 Авг 2010 в 12:07

Попробуй это

//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);
  }
}
-3
MarmiK 4 Ноя 2015 в 09:36

Простая реализация показа фрагмента текста каждые две секунды, пока работает цикл.

for (var i = 0; i < foo.length; i++) {
   setInterval(function(){ 
     console.log("I will appear every 2 seconds"); 
   }, 2000);
  break;
};
-1
squeekyDave 14 Ноя 2018 в 16:26

Попробуй это...

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);
}
-1
PHILL BOOTH 9 Май 2018 в 09:45

Этот скрипт работает для большинства вещей

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);
}
-1
Jaketr00 19 Мар 2016 в 02:00

Вот функция, которую я использую для цикла по массиву:

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
}
-1
PJeremyMalouf 2 Июн 2015 в 01:38

В 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 позволяет объявлять переменные, ограниченные областью действия оператора блока или выражения, в котором он используется, в отличие от ключевого слова var, которое определяет переменную глобально или локально на всю функцию независимо от объема блока.

1
Tabish 4 Мар 2020 в 05:05
   let counter =1;
   for(let item in items) {
        counter++;
        setTimeout(()=>{
          //your code
        },counter*5000); //5Sec delay between each iteration
    }
0
Ali Azhar 10 Окт 2019 в 21:02

Насколько мне известно, функция setTimeout вызывается асинхронно. Что вы можете сделать, это обернуть весь цикл в асинхронную функцию и ждать Promise, который содержит setTimeout, как показано:

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

Пожалуйста, найдите время, чтобы получить хорошее представление об асинхронном программировании.

0
Questionare232 23 Фев 2019 в 22:35
<!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>
0
Boginaathan M 23 Янв 2018 в 07:40

Для обычного использования «забудь нормальные циклы» и используй эту комбинацию «setInterval» включает «setTimeOut» s: like this (из моих реальных задач).

        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): они все начнутся в одно и то же время «три бла-бла-бла начнут обратный отсчет в один и тот же момент», поэтому сделайте другой тайм-аут, чтобы организовать выполнение.

PS 2: пример для цикла синхронизации, но для циклов реакции вы можете использовать события, обещают асинхронное ожидание ..

0
Mohamed Abulnasr 1 Дек 2017 в 08:27

Вот как я создал бесконечный цикл с задержкой, которая прерывается на определенное условие:

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

Ключевым моментом здесь является создание нового Обещания, которое разрешается по таймауту, и ждать его разрешения.

Очевидно, вам нужна поддержка async / await для этого. Работает в Узле 8.

0
27 Сен 2017 в 17:21
/* 
  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
*/
0
user2913925 24 Окт 2013 в 02:51

Ты делаешь это:

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>
1
Nguyen Ba Danh - FAIC HN 26 Ноя 2019 в 03:04
    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);

Модифицированная версия ответа Даниэля Вассалло с переменными, извлеченными в параметры, чтобы сделать функцию более пригодной для повторного использования:

Сначала давайте определим некоторые существенные переменные:

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
1
Jasdeep Khalsa 10 Мар 2016 в 15:22

Вы можете использовать RxJS оператор интервалов. Интервал выдает целое число каждые x секунд, а значение take указывает, сколько раз он должен выдавать числа

Rx.Observable
  .interval(1000)
  .take(10)
  .subscribe((x) => console.log(x))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script>
3
Vlad Bezden 23 Июн 2016 в 19:59

Я делаю это с Promise.delay Bluebird и рекурсией.

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

myLoop(3);
<script src="//cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.4/bluebird.min.js"></script>
4
user4642212 10 Июн 2018 в 23:50

Просто подумал, что я тоже выложу свои два цента. Эта функция запускает итерационный цикл с задержкой. Смотрите этот 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);
}
4
D Slee 4 Авг 2016 в 17:02

В ES6 (ECMAScript 2015) вы можете выполнять итерации с задержкой с помощью генератор и интервал.

Генераторы, новая функция ECMAScript 6, являются функциями, которые могут быть остановился и возобновил. Вызов genFunc не выполняет его. Вместо этого возвращает так называемый генераторный объект, который позволяет нам контролировать genFunc выполнение . genFunc () изначально приостанавливается в начале его тело . Метод genObj.next () продолжает выполнение genFunc, до следующего урожая. (знакомство с 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;
  }
}

Так что, если вы используете ES6, это самый элегантный способ добиться цикла с задержкой (на мой взгляд).

8
Itay Radotzki 7 Окт 2015 в 15:26

Это будет работать

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

Попробуйте эту скрипку: https://jsfiddle.net/wgdx8zqq/

14
Gsvp Nagaraju 5 Апр 2017 в 06:56

Я бы, наверное, использовал 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);
14
Abel Terefe 6 Июн 2013 в 13:48

Думаю вам нужно что-то вроде этого:

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, пока вы не закроете предупреждение. Это может быть больше кода, чем вы просили, но это надежное решение для повторного использования.

15
BGerrissen 27 Авг 2010 в 12:20

Другой способ - увеличить время ожидания, но учтите, что это не похоже на сон . Код после цикла будет выполнен немедленно, только выполнение функции обратного вызова откладывается.

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

Первый тайм-аут будет установлен на 3000 * 1, второй на 3000 * 2 и так далее.

23
Felix Kling 27 Авг 2010 в 11:48

Поскольку ES7 - лучший способ ждать цикла:

// Returns a Promise that resolves after "ms" Milliseconds
function timer(ms) {
 return new Promise(res => setTimeout(res, ms));
}

async function load () { // We need to wrap the loop into an async function for this to work
  for (var i = 0; i < 3; i++) {
    console.log(i);
    await timer(3000); // then the created Promise can be awaited
  }
}

load();

Когда движок достигает части await, он устанавливает тайм-аут и останавливает выполнение async function . Затем по истечении времени ожидания выполнение продолжается в этой точке. Это весьма полезно, поскольку вы можете отложить (1) вложенные циклы, (2) условно, (3) вложенные функции:

async function task(i) { // 3
  await timer(1000);
  console.log(`Task ${i} done!`);
}

async function main() {
  for(let i = 0; i < 100; i+= 10) {
    for(let j = 0; j < 10; j++) { // 1
      if(j % 2) { // 2
        await task(i + j);
      }
    }
  }
}
    
main();

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

Ссылка на MDN

Хотя ES7 теперь поддерживается NodeJS и современными браузерами, вы можете захотеть перенесите его с помощью BabelJS, чтобы он работал везде.

48
Jonas Wilms 12 Авг 2019 в 12:39

Если вы используете ES6, вы можете использовать let для достижения этой цели:

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

let делает то, что объявляет i для каждой итерации , а не цикла. Таким образом, то, что передается в setTimeout, именно то, что мы хотим.

65
Saket Mehta 15 Мар 2016 в 17:47

Попробуйте что-то вроде этого:

var i = 0, howManyTimes = 10;
function f() {
    alert( "hi" );
    i++;
    if( i < howManyTimes ){
        setTimeout( f, 3000 );
    }
}
f();
70
cji 27 Авг 2010 в 11:40