setTimeout question

M

Martin

Can I have two setTimeouts running at the same time - with two
different intervals?

I want to start one timer and, before it times out, start another one

I've tried this and they seems to interfer with one another.
 
M

Martin

Martin said the following on 4/3/2007 5:27 PM:

Yes. They don't even know about each other.


How so? Test page that shows them interfering?

I can't make a test page available to you but here's the code I'm
working with:

This is part of a page in which I'm using an httpRequest to display
some frequently changing information in a table. It's making the
request every 400 ms with the GetScanInfo function. When the data is
received and displayed, the background color of the row is set to
yellow. The ResetColor function is then called with a 700 ms delay to
change the color back to white. It is this ResetColor function that is
not executing.

Do you see anything wrong?

Thanks.




var http = getHTTPObject();
var TheRow;
function handleHttpResponse() {
var Msgs;
if (http.readyState == 4) {
if (http.status == 200) {
Msgs = http.responseText.split("|");
var gSP = parseInt(Msgs[1]);
TheRow = document.getElementById('TableX').rows[gSP];
if (TheRow.cells[5].innerHTML != Msgs[6]) {
TheRow.cells[1].innerHTML = Msgs[2];
TheRow.cells[2].innerHTML = Msgs[3];
TheRow.cells[3].innerHTML = Msgs[4];
TheRow.cells[4].innerHTML = Msgs[5];
TheRow.cells[5].innerHTML = Msgs[6];
TheRow.cells[1].title = 'Time Of Scan: ' + Msgs[6];
TheRow.style.backgroundColor = 'yellow';
window.setTimeout("ResetColor(gSP)",700);
}
NextSP = gSP + 1;
if (NextSP > 12) {NextSP = 1};
window.setTimeout("GetScanInfo(NextSP)",400);
}
}
}
function ResetColor(XX) {
document.getElementById('TableX').rows[XX].style.backgroundColor =
'white';
}

function GetScanInfo(SP) {
http.open("GET", "ScanInfo.HTM?" + SP, true);
http.onreadystatechange = handleHttpResponse;
http.send(null);
}
 
L

-Lost

Randy Webb said:
Martin said the following on 4/3/2007 5:27 PM:

Yes. They don't even know about each other.


How so? Test page that shows them interfering?

var timer1 = window.setTimeout('alert("first");', 1000);
var timer2 = window.setTimeout('window.clearTimeout("' + timer1 + '");', 500);

Believe it or not, I put something like this in my page once, forgot that I was fooling
with them, continued on with the page and could not figure out why nothing happened.

No errors, no anything. I started the script in motion... then halted it.

Dumb.

-Lost
 
R

RobG

I can't make a test page available to you but here's the code I'm
working with:

This is part of a page in which I'm using an httpRequest to display
some frequently changing information in a table. It's making the
request every 400 ms with the GetScanInfo function. When the data is
received and displayed, the background color of the row is set to
yellow. The ResetColor function is then called with a 700 ms delay to
change the color back to white. It is this ResetColor function that is
not executing.

Do you see anything wrong?

Yes, see below.

Also, it is a convention that variables starting with an upper case
letter indicate constructor functions, other variables should start
with a lower case letter, e.g. TheRow should be theRow.

var http = getHTTPObject();
var TheRow;
function handleHttpResponse() {
var Msgs;
if (http.readyState == 4) {
if (http.status == 200) {
Msgs = http.responseText.split("|");
var gSP = parseInt(Msgs[1]);

Here you declare gSP as a local variable within the handleHttpResponse
function.

TheRow = document.getElementById('TableX').rows[gSP];

Instead of passing a number to your ResetColor function, then having
to go through the whole getElementById thing again, store a reference
to the row and pass that (i.e. instead of passing gSP, pass TheRow).

if (TheRow.cells[5].innerHTML != Msgs[6]) {
TheRow.cells[1].innerHTML = Msgs[2];
TheRow.cells[2].innerHTML = Msgs[3];
TheRow.cells[3].innerHTML = Msgs[4];
TheRow.cells[4].innerHTML = Msgs[5];
TheRow.cells[5].innerHTML = Msgs[6];
TheRow.cells[1].title = 'Time Of Scan: ' + Msgs[6];
TheRow.style.backgroundColor = 'yellow';
window.setTimeout("ResetColor(gSP)",700);

There is no need to prefix setTimeout with window, unless you have a
local variable called setTimeout (which would be a bad idea).

setTimeout will run the code passed to it in a global scope. By that
stage, gSP has gone out of scope and will return "undefined". Pass an
anonymous function object with a closure back to gSP (or theRow)
instead:

setTimeout(function(){ResetColor(gSP)}, 700);

}
NextSP = gSP + 1;
if (NextSP > 12) {NextSP = 1};
window.setTimeout("GetScanInfo(NextSP)",400);

This call works because you have (inadvertently?) created NextSP as a
global variable.

}
}
}
function ResetColor(XX) {
document.getElementById('TableX').rows[XX].style.backgroundColor =
'white';

Instead of changing the background colour explicitly, consider just
changing the CSS class, then you only need modify a CSS rule if you
want a different colour combination (which is the point of CSS). :)
 
M

Martin

I can't make a test page available to you but here's the code I'm
working with:

This is part of a page in which I'm using an httpRequest to display
some frequently changing information in a table. It's making the
request every 400 ms with the GetScanInfo function. When the data is
received and displayed, the background color of the row is set to
yellow. The ResetColor function is then called with a 700 ms delay to
change the color back to white. It is this ResetColor function that is
not executing.

Do you see anything wrong?

Yes, see below.

Also, it is a convention that variables starting with an upper case
letter indicate constructor functions, other variables should start
with a lower case letter, e.g. TheRow should be theRow.

var http = getHTTPObject();
var TheRow;
function handleHttpResponse() {
var Msgs;
if (http.readyState == 4) {
if (http.status == 200) {
Msgs = http.responseText.split("|");
var gSP = parseInt(Msgs[1]);

Here you declare gSP as a local variable within the handleHttpResponse
function.

TheRow = document.getElementById('TableX').rows[gSP];

Instead of passing a number to your ResetColor function, then having
to go through the whole getElementById thing again, store a reference
to the row and pass that (i.e. instead of passing gSP, pass TheRow).

if (TheRow.cells[5].innerHTML != Msgs[6]) {
TheRow.cells[1].innerHTML = Msgs[2];
TheRow.cells[2].innerHTML = Msgs[3];
TheRow.cells[3].innerHTML = Msgs[4];
TheRow.cells[4].innerHTML = Msgs[5];
TheRow.cells[5].innerHTML = Msgs[6];
TheRow.cells[1].title = 'Time Of Scan: ' + Msgs[6];
TheRow.style.backgroundColor = 'yellow';
window.setTimeout("ResetColor(gSP)",700);

There is no need to prefix setTimeout with window, unless you have a
local variable called setTimeout (which would be a bad idea).

setTimeout will run the code passed to it in a global scope. By that
stage, gSP has gone out of scope and will return "undefined". Pass an
anonymous function object with a closure back to gSP (or theRow)
instead:

setTimeout(function(){ResetColor(gSP)}, 700);

}
NextSP = gSP + 1;
if (NextSP > 12) {NextSP = 1};
window.setTimeout("GetScanInfo(NextSP)",400);

This call works because you have (inadvertently?) created NextSP as a
global variable.

}
}
}
function ResetColor(XX) {
document.getElementById('TableX').rows[XX].style.backgroundColor =
'white';

Instead of changing the background colour explicitly, consider just
changing the CSS class, then you only need modify a CSS rule if you
want a different colour combination (which is the point of CSS). :)

Thank you, thank you, thank you! I could NOT figure this out! Your
solution worked perfectly.

Now I'd like to understand WHY it works.

After I had posted my original message, I had discovered that the
problem was that the gSP variable was "not defined" when the
ResetColor function was called. I couldn't figure out how that could
be the case and I still don't understand how it can be so.

The gSP variable is created and assigned a value INSIDE the
handleHttpResponse function. It is used INSIDE this function (to
select TheRow) and it is used again after the call to ResetColor where
it's incremented and assigned to NextSP.

While trying to figure this out, I inserted alerts in various places
and showed that the NextSP variable was, in fact, getting incremented
correctly - which meant that gSP still had it's value when it reached
that point in the routine. So, why wouldn't it get passed to
ResetColor?

I have yet to understand this. Could you possibly educate me or point
me to something where this is explained?

Again, thank you for fixing this for me - it's greatly appreciated.
 
R

RobG

There is no need to prefix setTimeout with window, unless you have a
local variable called setTimeout (which would be a bad idea).
setTimeout will run the code passed to it in a global scope. By that
stage, gSP has gone out of scope and will return "undefined". Pass an
anonymous function object with a closure back to gSP (or theRow)
instead:
setTimeout(function(){ResetColor(gSP)}, 700);
[...]

Thank you, thank you, thank you! I could NOT figure this out! Your
solution worked perfectly.

Now I'd like to understand WHY it works.

After I had posted my original message, I had discovered that the
problem was that the gSP variable was "not defined" when the
ResetColor function was called. I couldn't figure out how that could
be the case and I still don't understand how it can be so.

The gSP variable is created and assigned a value INSIDE the
handleHttpResponse function. It is used INSIDE this function (to
select TheRow) and it is used again after the call to ResetColor where
it's incremented and assigned to NextSP.
Precisely.


While trying to figure this out, I inserted alerts in various places
and showed that the NextSP variable was, in fact, getting incremented
correctly - which meant that gSP still had it's value when it reached
that point in the routine. So, why wouldn't it get passed to
ResetColor?

Because you don't call ResetColor at that point, you pass a *string*
to setTimeout, which evaluates the string at some later time as global
code after the handleHttpResponse function has finished. gSP never
had global scope (in accordance with good practice you declared as
local to handleHttpResponse), so setTimeout can't access it even if it
still exists.

I have yet to understand this. Could you possibly educate me or point
me to something where this is explained?

The issue is explained very thoroughly by Richard Cornford here:

<URL: http://www.jibbering.com/faq/faq_notes/closures.html >

where setTimeout is used as an example. I seem to be posting that
reference quite a lot lately. :)

The reason that the solution works is that it creates an anonymous
function object in the scope of the handleHttpResponse function and
passes that to setTimeout. This anonymous function has a closure back
to the gSP variable, so it can be resolved when setTimeout runs the
code.

The closure causes the variable (and probably the entire activation
object it is a property of) to still exist. Once setTimeout has run,
if gSP was the only reference to that activation object, then it (the
activation object) is made available for garbage collection.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top