Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 13 of 13
  1. #1
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts

    Question about setTimeout()

    Hi all,

    I am trying to do a simple "animation" of the background color of a button. I want it to do 10 different colors in the course of 1 second. I have a loop like this (pseudo code):

    Code:
        var e = "the button element";
        var c = 10;
        while (c--) {
            setTimeout(function(){ e.style.backgroundColor=(random color); }, (c * 100));
        }
    I expect that 10 instances of "setTimeout" would be created, each one timing out 0.1 seconds later than the previous one, giving me an "animation" of 10 different colors over the course of 1 second.

    Strangely, it doesn't work. All it does is WAIT one second, then set the background to the LAST color.

    What am I doing wrong? I can't see it.

    Thanks!

    -- Roger

    Edit:
    I also tried to do the loop forward instead... no difference.
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #2
    The fat guy next door VIPStephan's Avatar
    Join Date
    Jan 2006
    Location
    Halle (Saale), Germany
    Posts
    8,607
    Thanks
    6
    Thanked 997 Times in 970 Posts
    For repeating functions you should rather look into setInterval(). And to stop the repetition there is clearInterval().

  • #3
    Regular Coder
    Join Date
    Aug 2010
    Posts
    966
    Thanks
    19
    Thanked 211 Times in 209 Posts
    Here is a solution using setTimeout ...

    PHP Code:
    <script>

    running false;
    function 
    changeColor(el){
        if (
    running) return;
        
    running true;
        
    colorIndex 0;
        
    color = ["green","blue","silver","yellow","red"]

        function 
    changeIt(){
            
    el.style.backgroundColor color[colorIndex];
            
    colorIndex++;
            if(
    colorIndex == 5){
                
    colorIndex 0;
                
    running false;
                return;}
            
    setTimeout(changeIt,500);
        };
        
    changeIt()
    }

    </script>

    <div style="height:100;width:100;background:red;" onclick="changeColor(this)">click me</div> 

  • Users who have thanked DaveyErwin for this post:

    Krupski (07-26-2011)

  • #4
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts
    Quote Originally Posted by VIPStephan View Post
    For repeating functions you should rather look into setInterval(). And to stop the repetition there is clearInterval().
    I don't want to repeat a function (like say, update a live clock once a second).

    I want to do a number of different things in spaced time intervals.

    For example, I want this:

    Code:
    Time: 0.0sec  Color: red
    Time: 0.1sec  Color: green
    Time: 0.2sec  Color: blue
    ......
    ......
    Time: 1.0sec  Color: gray
    (loop ends)
    setInterval would not do the trick (I don't think?)...
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #5
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts
    Quote Originally Posted by DaveyErwin View Post
    Here is a solution using setTimeout ...

    PHP Code:
    <script>

    running false;
    function 
    changeColor(el){
        if (
    running) return;
        
    running true;
        
    colorIndex 0;
        
    color = ["green","blue","silver","yellow","red"]

        function 
    changeIt(){
            
    el.style.backgroundColor color[colorIndex];
            
    colorIndex++;
            if(
    colorIndex == 5){
                
    colorIndex 0;
                
    running false;
                return;}
            
    setTimeout(changeIt,500);
        };
        
    changeIt()
    }

    </script>

    <div style="height:100;width:100;background:red;" onclick="changeColor(this)">click me</div> 
    OH!!! I see! That's really neat. The code actually gets called probably almost a million times, but the "running" flag controls it. Very clever! Thank you! I understand.

    -- Roger
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #6
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts

    Question

    I still wonder though... why didn't my original method work? Is it Javascript illegal to have more than one instance of setTimeout() running at a time?
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #7
    Regular Coder
    Join Date
    Aug 2010
    Posts
    966
    Thanks
    19
    Thanked 211 Times in 209 Posts
    Quote Originally Posted by Krupski View Post
    I still wonder though... why didn't my original method work? Is it Javascript illegal to have more than one instance of setTimeout() running at a time?
    Your code sets 10 timeouts in a loop that runs
    very fast so they all time out together .

  • #8
    Regular Coder
    Join Date
    Aug 2010
    Posts
    966
    Thanks
    19
    Thanked 211 Times in 209 Posts
    Quote Originally Posted by Krupski View Post
    OH!!! I see! That's really neat. The code actually gets called probably almost a million times, but the "running" flag controls it. Very clever! Thank you! I understand.

    -- Roger
    No , I don't think you do.
    The running flag prevents changeColor
    from running again until it is reset by
    changeIt.
    changeIt sets a timeout that calls itself
    so it runs after each timeout untill colorIndex
    is incremented to 5 then no more time outs
    are set and the running flag is set to false
    so changeColor can be run again. Without
    the running flag changeIt could be run again
    by clicking the div before changeIt has finished.
    You don't want it to run again till its finished.

  • #9
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts
    Quote Originally Posted by DaveyErwin View Post
    Your code sets 10 timeouts in a loop that runs
    very fast so they all time out together .
    Yes, 10 instances are called virtually at the same time, but each one has a different timeout value which should make them operate sequentially.

    It's like imagine 10 cars. Fill the first with one gallon of gasoline, the second one with two, etc... then start them driving at the same time.

    They should all stop at progressively further and further away points based on how much gasoline was put in. Each car at a different distance, EVEN THOUGH they started at the exact same time.
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #10
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts
    Quote Originally Posted by DaveyErwin View Post
    No , I don't think you do.
    The running flag prevents changeColor
    from running again until it is reset by
    changeIt.
    changeIt sets a timeout that calls itself
    so it runs after each timeout untill colorIndex
    is incremented to 5 then no more time outs
    are set and the running flag is set to false
    so changeColor can be run again. Without
    the running flag changeIt could be run again
    by clicking the div before changeIt has finished.
    You don't want it to run again till its finished.
    Yes you are correct. When I first glanced at the code, I thought it kept calling itself as fast as it could but kept from restarting the timeout with the "running" flag.

    Now that I look at it more carefully, I see how it's working.

    Getting back to the setTimeout thing, it's strange if I put 10 discrete lines one after the other, they work!

    THIS works perfectly:

    Code:
    var e = whereTheResultIsDisplayed;
    setTimeout(function(){ e.innerHTML = 1; }, 1000);
    setTimeout(function(){ e.innerHTML = 2; }, 2000);
    setTimeout(function(){ e.innerHTML = 3; }, 3000);
    .......... etc........
    setTimeout(function(){ e.innerHTML = 9; }, 9000);
    But putting the same thing in a loop fails. I just don't get it.

    I know in the above code all 10 lines are run virtually at the same instant, yet they time out 1 second apart (as they should).

    I just don't see the difference.
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov

  • #11
    Regular Coder
    Join Date
    Aug 2010
    Posts
    966
    Thanks
    19
    Thanked 211 Times in 209 Posts
    Quote Originally Posted by Krupski View Post
    Yes, 10 instances are called virtually at the same time, but each one has a different timeout value which should make them operate sequentially.

    It's like imagine 10 cars. Fill the first with one gallon of gasoline, the second one with two, etc... then start them driving at the same time.

    They should all stop at progressively further and further away points based on how much gasoline was put in. Each car at a different distance, EVEN THOUGH they started at the exact same time.
    DOUGH of course your right, my mistake,sorry.

    look this over ...

    PHP Code:
    <html>

    <
    script>
    running false;
    function 
    changeColor(el){
        if(
    running)return;
        
    running true;
        
    color = ["green","blue","silver","yellow","red"
            var 
    5;
        var 
    0;
            while (
    c--) {setTimeout(changeIt, (1000));}
        function 
    changeIt(){
            
    el.style.backgroundColor=color[d++];
            if (
    == 5)running false;        
            }
        }

    </script>
    <body>


    <div style="height:100;width:100;background:red;" onclick="changeColor(this)">click me</div> 


    </body>
    </html> 

  • #12
    Regular Coder
    Join Date
    Aug 2010
    Posts
    966
    Thanks
    19
    Thanked 211 Times in 209 Posts
    This one will answer some questions or
    maybe just really confuse you ...

    PHP Code:
    <script>

    "hello"

    function timeIt(){
    var 
    "hi";
    setTimeout("alert('"+a+"')",1000);

    setTimeout("alert(a)",3000);}
    timeIt();
    </script> 
    the first alert says hi
    the second says hello

    Why?

    Because the delayed code is run
    in the 'global' or 'window' context.

    It sees the global var a
    which equals hello not the
    local var a which equals hi.

    the first timeout uses the
    'value' of the local var a.

  • Users who have thanked DaveyErwin for this post:

    Krupski (07-27-2011)

  • #13
    Regular Coder Krupski's Avatar
    Join Date
    Dec 2010
    Location
    United States of America
    Posts
    505
    Thanks
    39
    Thanked 47 Times in 46 Posts
    Quote Originally Posted by DaveyErwin View Post
    This one will answer some questions or
    maybe just really confuse you ...
    I found the problem. It got up and slapped me in the head!

    Putting the setTimeout in a loop and using the loop counter as the timeout variable made the timeout of EACH instance to be the same number.

    If I put the setTimeout in a separate function and CALL it with the loop, each instance gets is't own private variable and of course it works.

    I had a similar problem with a SELECT / OPTION loop. I used a loop to generate the HTML for a select/option dropdown and had the onchange call a function with the loop counter as a parameter (thinking that each one was generated separately).

    To my surprise, selecting any option yielded the same number... the end of the loop counter!

    I finally figured out what was happening and changed it to pass this.value instead and ta-da it worked.

    The more I learn. the more I don't know!

    Thanks again for all the help!

    -- Roger
    "Anything that is complex is not useful and anything that is useful is simple. This has been my whole life's motto." -- Mikhail T. Kalashnikov


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •