Jump to content

Javascript - Settimeout & Recursion


eggrock
 Share

Recommended Posts

Using the following code, I expect to have varying bits of information placed on the page every few seconds:

 

>function newsbar(count, delay)
{
 var newsitem = new Array();
 newsitem[0] = "some news";
 newsitem[1] = "more news";

 for (i=0;i<newsitem.length;i++)
 {
if(count==i)
{
  document.newsform.newsinput.value=newsitem[i];
  count++;
  if(count>=newsitem.length)
  {
	count = 0;
  }
  news=setTimeout("newsbar(count, delay)", delay);
}
 }
}

 

The script is called in the body tag, eg <body onload="newsbar(0, 5000);">, and placement is in a text input box (form name is 'newsform' and the input name is 'newsinput'.

 

A couple problems:

 

- Even though I pass '0' (as count) in the onload tag, array element 1 displays. This tells me that 'i' is being incremented differently than I'd expect; guessing as soon as 'i++' is encountered. Not a huge deal.

 

- The big problem is, when setTimeout is used to call newsbar again, count (and probably delay) are undefined. I don't know what's going on there. Every example I see on the web is either passing a string to the function (which works in my case) or nothing at all. No actual variable values are passed so this has to be yet another feature *coughidiocycough* of Javascript, or maybe just a quirk of setTimeout or whatever, I dunno.

 

For efficiency's sake I can probably initialize that array externally to the function but since I'm basically illiterate when it comes to Javascript I'm playing it safe for now. The rules in Javascript are so incomprehensible I'm willing to sacrifice elegance and efficiency in the name of functionality.

Edited by eggrock
Link to comment
Share on other sites

One answer I got elsewhere was to change

 

>news=setTimeout("newsbar(count, delay)", delay);

 

to this

 

>myCmd = 'newsbar(' + count + ', ' + delay + ')'
news = setTimeout(myCmd, delay)

 

And make count global, or at least external to the function call. With some other tweaks and messing around, count will start at 0, increment and then roll over back to 0 when it reaches the value of the total number of array elements. Exactly what I want.

 

Trouble is, 'newsitem[count]' still doesn't display correctly; it doesn't change at all on the web page.

 

So I guess what I'm really after is something that explains EXACTLY how Javascript handles variables and why you need to do this funky string concatenation to pass things along. The latter probably has to do with how quotes are handled. It doesn't act like I expect it to--you know, C, Perl, reverse Polish notation on HP calculators. :P

 

I've been using W3 schools and code samples from various places but the documentation is far from complete.

Link to comment
Share on other sites

So I guess what I'm really after is something that explains EXACTLY how Javascript handles variables and why you need to do this funky string concatenation to pass things along. The latter probably has to do with how quotes are handled. It doesn't act like I expect it to--you know, C, Perl, reverse Polish notation on HP calculators. :P

What you're encountering is a variable scoping issue, which isn't something specific to javascript (it can occur in C, PHP, perl, etc.).

 

The variables 'count' and 'delay' are defined as parameters passed to the 'newsbar' function':

>function newsbar(count, delay)

These variables exist only within the function 'newsbar' code - javascript code outside of function 'newsbar' cannot see these variables.

 

Near the end of the 'newsbar' code, the function calls setTimeout to schedule another run of the function:

>news=setTimeout("newsbar(count, delay)", delay);

Basically, the "newsbar(count, delay)" is stored as text, and the 'newsbar' function code continues to execute (and eventually exits). When the 'delay' interval has passed (5 seconds in this case), the browser retrieves the text set with setTimeout and evaluates it. The function 'newsbar' can be found easily enough, but the variables 'count' and 'delay' at this point do not exist, because the 'newsbar' function finished executing a little less than 5 seconds ago.

 

>myCmd = 'newsbar(' + count + ', ' + delay + ')';
news = setTimeout(myCmd, delay);

The first line in the above code constructs the string that will be set in the setTimeout function call in the second line. The 'count' and 'delay' variables are evaluated while they are still in scope and accessible. Instead of setting "newsbar(count, delay)" to be called 5 seconds later, this code would set something like "newsbar(1, 5000)". Since there are no variables in this function call, there won't be any problems with variables not being defined and accessible due to scoping.

 

I'm not sure why you have a for loop in the 'newsbar' function. From what I can tell, it does not appear to be necessary:

>function newsbar(count, delay)
{
 var newsitem = new Array();
 newsitem[0] = "some news";
 newsitem[1] = "more news";

 document.newsform.newsinput.value=newsitem[count];
 count++;
 if(count>=newsitem.length)
 {
count = 0;
 }
 myCmd = 'newsbar(' + count + ', ' + delay + ')';
 news = setTimeout(myCmd, delay);
}

The two lines of code you added to the script should have a ';' at the end of each line. Not having them could account for the text not changing when you tested the script.

 

I tested the above code in both IE and Firefox, and it seems to work okay for me.

 

Hope this helps...

Link to comment
Share on other sites

This wound up working; setTimeout does operate (or execute) in a global scope--which makes sense since it's an event--so the declaration/initialization of 'count' and 'delay' need to be external to the function as well, or else the local scope overrides the global scope and I get undefined values as a result. With everything in a global scope there's no need for looping with the exception of the recursive function call:

 

>var newsitem = new Array();
var delay = 7000;
var count = 0;
newsitem[0] = "some news";
newsitem[1] = "more news";

function newsbar()
{
var newsmsg = "News: " + newsitem[count];
document.newsform.newsinput.value=newsmsg;
count++;
if(count >= newsitem.length)
{
 count = 0;
}
news=setTimeout("newsbar()", delay);
}

 

That's still a bit unclear because the tutorials and explanations I've seen indicate that 'count = 0' is the same as 'var count = 0', so there must be a check for a predefined global before a local is created.

 

[edit] And the results are here: http://up-nort.com/test/cfbtest1/index.html - Still playing around with layout, backgrounds and such but once the javascript is done it's all layout and server side (the latter is complete as well).

Edited by eggrock
Link to comment
Share on other sites

That's still a bit unclear because the tutorials and explanations I've seen indicate that 'count = 0' is the same as 'var count = 0', so there must be a check for a predefined global before a local is created.
Those statements are the same outside of a function, but not within one:
The var statement is used to declare a variable, and outside of a function its use is optional. While a variable can be declared simply by assigning it a value, it is good practice to use var as there are two cases in functions where it is necessary:

 

- If a global variable of the same name exists.

 

- If recursive or multiple functions use variables of the same name.

I'm glad to hear you finally got it working! :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...