for循环中的JavaScript setTimeout

时间:2014-04-04 14:17:05

标签: javascript for-loop settimeout repeat hypertalk

我之前已经看到这个问题已被提出过,但我不确定能解决我的问题。

我有以下代码:

function mouseup (  )
{
    for( i = 0; i < 6; i++ )
    {
        setTimeout(function(){
            alert( "test" );
        },1000);
    } 
}

但是当我运行代码时,暂停一秒钟后,对话框出现(应该如此),但是当我在该对话框上单击“确定”时,第二个立即出现,没有任何延迟。

jsFiddle example

有没有一种简单的方法可以在不改变太多代码的情况下解决这个问题? 我问的原因是因为我正在构建一个改变代码的转换器,如:

repeat 6 times
    wait for 1 second
    answer "test"
end repeat

进入上面的JavaScript代码,如果我没有,也不想改变我的转换程序太多。

非常感谢提前。

编辑: (如果您想知道,非JavaScript代码是HyperTalk / xTalk代码)

8 个答案:

答案 0 :(得分:8)

window.counter = 6;
function mouseup (  )
{
    setTimeout(function(){
        alert( "test" );
        if ( window.counter-- ) {
            mouseup (  );
        }
    },1000);
}

答案 1 :(得分:6)

使用for循环无法达到你想要的效果。在继续之前,for循环不会等待超时。要做你想做的事情,你需要将你的超时链接在一起,以便结束一个超时开始下一个超时:

var i = 0;
function TimeoutFired() {
    i++;
    alert( "test" );
    if (i < 6) {
        setTimeout(TimeoutFired, 1000);
    }
}
setTimeout(TimeoutFired, 1000);

http://jsfiddle.net/M98ZL/

答案 2 :(得分:2)

作为另一种解决方案,您可以使用setInterval,然后执行6次清除

function mouseup (  )
{
    var i=0;
    var myVar = setInterval(function(){

        alert("test")
        i++;
        if(i===6){clearInterval(myVar);}                      
    },1000);

}

DEMO

答案 3 :(得分:1)

function mouseup (  )
{
    var delay = 0;
    for( i = 0; i < 6; i++ )
    {
        setTimeout(function(){
            alert( "test" );
        },(delay += 1000));
    } 
}

答案 4 :(得分:1)

虽然这里已有一些解决方案,但我想展示一些其他解决方法。 (此代码不测试错误,只是你知道你可以做什么)

 function loop( from, to, callback, finished ) {
   var currIdx = from-1;

   function next() {
     currIdx++;
     if( currIdx < to ) {
       callback(currIdx, next, stop);
     } else {
       if( finished ) {
         finished();
       }
     }
   }

   function stop() {
     if( finished ) {
       finished();
     }
   }
   next();


 }


 loop( 0, 6, function( i, next, stop ) {
   console.log(i);

   setTimeout(function() {
     next();
   }, 1000);

 });

这将允许您将next和/或stop回调传递给其他函数,从而允许您以简单的方式创建具有异步代码的循环。对于更复杂的事情,我建议你也看一下像whenjs这样的承诺库。

答案 5 :(得分:0)

You can do this in three different ways


1. with IIFE
------------

let fruits = ["banana", "apple", "Orange"];

for (let index = 0; index < fruits.length; index++) {
  (function(fruits, index) {
    setTimeout(() => {
      console.log(fruits[index]);
    }, index * 1000);
  })(fruits, index);
}



2. with Closure, as it reference the outer scope variable even after 
      the main function execution
----------------------------------

let fruits = ["banana", "apple", "Orange"];
function closerWithsettimeout() {
    return function() {
        fruits.forEach(function(elem, i) {
            setTimeout(() => {
                console.log(elem);
            }, 1000 * i);
        });
    };
}
closerWithsettimeout()();



3. With promise
----------------
let fruits = ["banana", "apple", "Orange"];

fruits.forEach((elem, i) => {
  var p = new Promise((resolve, reject) => {
    fruits[0] === "banana" ?
      setTimeout(() => {
        resolve(elem);
      }, i * 1000) :
      reject(new Error("Fruits cannot be bought"));
  });
  p.then(result => console.log(result)).catch(err => console.log(err.message));
});

答案 6 :(得分:0)

这个问题现在已经有多个好的答案,但是由于它们都没有提到async-await,因此,我想提出一个使用它的解决方案。如果您的目标是对原始代码进行尽可能少的更改,那没有比这更好的了。

async function mouseup (  )
{
    for( i = 0; i < 6; i++ )
    {
        await new Promise(function(resolve) {
            setTimeout(function(){
                alert( "test" );
                resolve();
            },1000);
        });
    } 
}

答案 7 :(得分:0)

此问题是由HyperTalk引起的,它使您可以依次执行脚本命令执行,而JavaScript仅按顺序触发

从ES7开始,JavaScript现在可以让您使用async / await顺序执行代码。

转换示例:

// Procedure to invoke upon mouseUp //
async function mouseup() {
    for( i = 0; i < 6; i++ ) {
        await myscript();
    } 
}

// Script to be invoked inside the for loop //
async function myscript() {
    setTimeout(function(){
        alert( "test" );
    },1000);
}

// Note: this does not include error trapping

请注意,使用JavaScript,您需要捕获mouseUp事件(不等同于将其放入对象脚本中,以通过内置陷阱(如HyperCard)触发)。

以前的JavaScript做法是在DOM元素(例如button)中引用单个事件触发器,但当前的做法是将其捕获在常规侦听器中。有几种方法可以做到这一点(例如,侦听元素ID中的'click'事件,或侦听指向高级项目的气泡并仅过滤所选元素中的内容)。

可以在https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

中找到用于收听JavaScript点击或(如果需要的话,可以使用鼠标)的语法。