最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript setTimeout inside for loop - Stack Overflow

programmeradmin0浏览0评论

I saw that this question has already been asked previously, but I was not sure of a solution to my problem.

I have the following code:

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

But when I run the code, after a one second pause, the dialog box es up (as it should), but when I click OK on that dialog box, the second immediately es up, without any delay.

jsFiddle example

Is there an easy way to fix this without changing too much of the code? The reason I ask is because I am building a converter that changes code such as:

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

into the JavaScript code above, and do not want to change too much of my converter program if I do not have too.

Many thanks in advance.

Edit: (and if you are wondering, the non-JavaScript code is HyperTalk/xTalk code)

I saw that this question has already been asked previously, but I was not sure of a solution to my problem.

I have the following code:

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

But when I run the code, after a one second pause, the dialog box es up (as it should), but when I click OK on that dialog box, the second immediately es up, without any delay.

jsFiddle example

Is there an easy way to fix this without changing too much of the code? The reason I ask is because I am building a converter that changes code such as:

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

into the JavaScript code above, and do not want to change too much of my converter program if I do not have too.

Many thanks in advance.

Edit: (and if you are wondering, the non-JavaScript code is HyperTalk/xTalk code)

Share Improve this question asked Apr 4, 2014 at 14:17 user2370460user2370460 7,82011 gold badges34 silver badges46 bronze badges 4
  • 1 Your code is asking to display 6 alert boxes all at roughly the same time 1 second from now. – CoderDennis Commented Apr 4, 2014 at 14:20
  • Your loops executes in microseconds, thus the alerts will all happen 1 second (+ a couple of microsends after) – cloakedninjas Commented Apr 4, 2014 at 14:20
  • There is no wait or sleep in js. Depending on what you exactly want to achieve there are different ways to solve this. – t.niese Commented Apr 4, 2014 at 14:20
  • possible duplicate of Python while loop conversion to Javascript – Bergi Commented Apr 4, 2014 at 14:21
Add a ment  | 

8 Answers 8

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

You can't achieve what you want like that with a for loop. The for loop won't wait for the timeout before continuing. To do what you want, you will need to chain your timeouts together so that ending one timeout starts the next one:

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

http://jsfiddle/M98ZL/

As onother solution-way you can use setInterval and after it executes 6 times clear it

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

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

}

DEMO

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

While there are already some solutions here i would like to show some other way to solve. (This code does not test for error, it is just that you get an idea what you could do)

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

 });

This would allow you to pass the next and/or stop callback to other function allowing you to create loops with async code in an easy way. For more plex things i would suggest to also look at a promise library like whenjs.

This question now already has multiple good answers but since none of them mentions async-await, I'd like to present a solution using it. If your goal is to make as few changes as possible to your original code, it doesn't get better than this.

async function mouseup (  )
{
    for( i = 0; i < 6; i++ )
    {
        await new Promise(function(resolve) {
            setTimeout(function(){
                alert( "test" );
                resolve();
            },1000);
        });
    } 
}
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));
});

This issue is caused by HyperTalk letting you write script mands to be executed sequentially, whilst JavaScript only fires them sequentially.

Since ES7, JavaScript can now let you use async/await to execute code sequentially.

An example conversion:

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

Note, with JavaScript, you would need to trap the mouseUp event (there is no equivalent to just putting it in the object's script to trigger via an inbuilt trap, like in HyperCard).

Previous JavaScript practice was to reference a single event trigger in the DOM element (e.g. button), but current practice is to trap it in a general listener instead. There are a few ways to do this (e.g. listen for 'click' event from the element ID, or listen for a bubble to a more senior item and filter for only those from your chosen element).

The syntax for listening to the JavaScript click or (mouseup if you prefer) can be found at https://developer.mozilla/en-US/docs/Web/API/EventTarget/addEventListener

发布评论

评论列表(0)

  1. 暂无评论