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

501

我想在一个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'),然后再等待3秒钟显示第二次 alert('hello'),以此类推。


for(var i=0; i < 5; i++){ delayLoop(i) }; function delayLoop(i){ setTimeout(function(){ console.log('每隔1秒打印一次', (i*1000)) } } - mhndlsz
const setTimeOutFn = async() => { for (var start = 0; start < 3; start++) { await new Promise(async(res, rej) => { setTimeout(() => { console.log('你好', start); res() }, 3000); }) } } - Bilal Khursheed
在每个循环中设置不同值的超时可能不是一个好主意。以下是一种使用Promise(async / await)实际上通过无限期挂起代码执行的无聊单行程序:https://dev59.com/DHA65IYBdhLWcg3w4C0L#73588338 - marko-36
33个回答

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

能否再多解释一下呢?相较于这里的其他40个答案之一,为什么我应该尝试这个方法?它是如何工作的,有哪些优点呢?谢谢。 - ggorlen

0

对于常见的使用场景,"忘记普通循环",使用这种包含 "setTimeOut" 的 "setInterval" 组合:像这样(来自我的真实任务)。

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

附注:请理解(setTimeOut)的真实行为:它们都将在同一时间开始,“三个bla bla bla会同时开始倒计时”,因此要设置不同的超时时间以安排执行。

PS 2:这是一个定时循环的示例,但是对于反应循环,您可以使用事件、Promise、async await等。


0

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

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

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函数的计时器到期时,该函数无限期地再次调用自身,但在每次调用时,数组都会变小,直到达到基本情况。我希望这可以帮助其他人。


这实际上并不是递归。在 setTimeout 回调运行之前,调用堆栈必须清除。 - ggorlen
递归函数是在执行期间调用自身的函数。该过程可能会重复多次,在每次迭代结束时输出结果。
  • 此函数调用自身。我看不出为什么这不是递归。
- Oushima
从代码的角度来看是正确的,但从应用程序的角度来看并不是递归的,因为调用堆栈会完全清除。在大多数递归函数中,调用会等待递归子帧将控制权返回给父级,然后才能解决自身问题,但这在这里并没有发生。实际上这是一件好事,因为你无法像在JS中的传统递归同步函数那样通过这段代码来清空堆栈。 - ggorlen

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。在 Node 8 中可以使用。

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

1
这忽略了在循环内设置延迟的要求。只是在5秒间隔上设置一系列事件(也可以使用setInterval)。为了更好地理解问题,请使用alert并等待5秒钟再点击“确定”。下一个警报将立即显示,没有延迟。 - niry

0
一个简单但不太优雅的解决方案是嵌套第二个循环,它将充当计时器(实质上,嵌套循环将保持线程)。如果你只是写一些临时的东西,这是一个不太正规的解决办法。
for(i=0;i<arr.length;i++){
   //you logic here

   //this will act as a timer
   for(j=0;j<25000;j++) console.log("")
}

上周我需要从一个网站下载大约40个文件,所以我写了一个简短的JS脚本通过Chrome的控制台执行,并且嵌套循环的技巧在延迟执行方面表现得非常出色。

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

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

为什么我应该尝试这个?这与其他几十个现有答案有何不同/更好之处? - ggorlen

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

8
你的函数命名太糟糕了,这就是这段代码难以阅读的主要原因。 - Mark Walters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接