...

View Full Version : Question about setTimeout()



Krupski
07-26-2011, 03:08 PM
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):



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


I also tried to do the loop forward instead... no difference.

VIPStephan
07-26-2011, 04:22 PM
For repeating functions you should rather look into setInterval() (https://developer.mozilla.org/En/window.setInterval). And to stop the repetition there is clearInterval().

DaveyErwin
07-26-2011, 04:35 PM
Here is a solution using setTimeout ...


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

Krupski
07-26-2011, 05:29 PM
For repeating functions you should rather look into setInterval() (https://developer.mozilla.org/En/window.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:



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?)...

Krupski
07-26-2011, 05:32 PM
Here is a solution using setTimeout ...


<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

Krupski
07-26-2011, 05:34 PM
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?

DaveyErwin
07-26-2011, 05:54 PM
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 .

DaveyErwin
07-26-2011, 06:05 PM
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.

Krupski
07-26-2011, 09:37 PM
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.

Krupski
07-26-2011, 09:45 PM
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:



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. :confused:

DaveyErwin
07-26-2011, 10:27 PM
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 ...


<html>

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

</script>
<body>


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


</body>
</html>

DaveyErwin
07-26-2011, 11:03 PM
This one will answer some questions or
maybe just really confuse you ...


<script>

a = "hello"

function timeIt(){
var a = "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.

Krupski
07-27-2011, 05:03 PM
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! :D

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



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum