reptile7's JavaScript blog
Monday, May 29, 2006
 
Towards the Infinite Loop
Blog Entry #40

Suppose you are an engineer designing a process that involves a repeating operation. Being efficiency-minded, you naturally seek to automate that operation if at all possible. So it is with computer programmers - engineers themselves in their own way - who might want to execute repeatedly a given block of code; the automative tools available to programmers include:
(a) functions - recall, for example, the recursive guessnum2( ) function in Blog Entry #38;
(b) loops;
and at least as far as JavaScript is concerned, the window object has
(c) a setInterval( ) method that "[e]valuates an expression or calls a function every time a specified number of milliseconds elapses," quoting Netscape.

At the beginning (in "The Concept") of HTML Goodies' JavaScript Primers #24, Joe notes that JavaScript has two main looping processes: for loops and while loops, which we'll discuss respectively in this and the next posts. Syntactically, for and while loops, like if...else conditionals, are classified in JavaScript as statements, so I'll be coloring their text references green as well.

We've actually encountered for loops twice previously, specifically in Blog Entries #12 and #17, but we have yet to discuss them in general terms, so let's do that now. Courtesy of Netscape, the syntax of a for loop is given below; as you can see, it has obvious similarities with the syntaxes of functions and if...else statements:

for ([initial-expression]; [condition]; [increment-expression])
// as long as the central condition is true, execute the following code repeatedly
{
command_statement_A;
command_statement_B; etc.
}
/* as usual, the braces surrounding the command statements do not need to be on their own lines; also, as for if and else, the braces can be omitted if there's just one statement */

After the for keyword is a set of parentheses generally containing three expressions, all of which are in fact optional, as indicated by the square brackets surrounding them.

The initial-expression usually initializes a counter variable, which can be but does not need to be declared with the var keyword - e.g., x=1; - however, you can put other types of statements (window.alert("Hello World");, document.bgColor="blue";, etc.) here* if for some reason you wanted to do that.
(*This is also true for the increment-expression.)

The increment-expression is typically used to update the value of the counter variable as the loop runs; the counter variable is most often incremented (1 is added to its value) here by one of the following commands:

x=x+1 // or...
x++ // or...
++x
/* ++ is the increment operator; it can precede or follow the counter variable in the increment-expression */

For count-controlled loops, Wikipedia notes, "In most cases counting can go downwards [e.g., the counter variable can be decremented] instead of upwards and step sizes other than 1 can be used."

The central condition commonly compares the counter variable with some other quantity and is evaluated at the beginning of each iteration of the loop; if the condition is true, then the loop code in braces executes repeatedly, as noted above, but if and when the condition becomes false, then the loop stops.

If you would like a mathematical analogy, the execution of a for loop is somewhat like obtaining a definite integral, , which also involves a repeating operation (the product f(x)dx) carried out according to a starting point (x = a) and a condition (a ≤ x ≤ b) and whose end result is the sum of the returns of the operation.

Although each for expression is optional, the semicolons delimiting them are not (you'll get errors if you leave them out). Suppose you want to leave out the condition expression; the syntax would look like:

for (x=1; ; x++) {statements}

With respect to the preceding code, perhaps you are thinking, "Wouldn't this set up an infinite loop?" Not to worry - a for (or while) loop can be terminated at a given point by a break statement, for example:

for (x=1; ; x++) {
if (x == 4) break
statements}

The statements of this loop execute three times before the loop is stopped by the if (x == 4) break command line. In effect, the break statement brings the for condition into the {body} of the loop; moreover, the increment-expression can also be placed in the loop body, if desired. For its part, the initial-expression can be placed prior to the loop statement but not in the loop body (unless you really do want to set up an infinite loop).

Netscape notes that the JavaScript for loop is similar to the for loops of the C and Java programming languages and provides a sequence of events for a JavaScript for loop here.

We're ready now for a quick look at the Primer #24 Script:

<html><head></head><body>
<h3>We'll now count from one to five:</h3>
<script type="text/javascript">
for (i=1; i<=5; i=i+1) {
document.write(i + "<br>"); }
</script>
<p>...and we're done
</body></html>

For the most part (notwithstanding the i > 5 typo that begins the fourth list item), Joe's script deconstruction is well done and I encourage you to read through it. Anything new here besides the for loop itself? Yes, actually - the for condition introduces the <= (less than or equal to) comparison operator, equivalent to the ≤ symbol.

The loop in the script runs five times, once for each value (1, 2, 3, 4, and 5) of the counter variable i; the loop condition, i<=5;, evaluates to false after i increments to 6 at the end of the fifth iteration, so the loop stops at this point. For each pass through the loop, the command:

document.write(i + "<br>");

prints the value of i and includes a <br> tag for carriage-returning the next value of i to the next line, as shown in the script demo.

The Primer #24 Assignment

In the Primer #24 Assignment, Joe asks the reader to create a document that uses two for loops as timers to schedule two executions of code. In theory, here's the sequence of events that's supposed to happen for a working answer:
(i) the user initially sees a page with a white background and an <h2>Hold on to Your Hat!</h2> header;
(ii) a first for loop counts to 10,000;
(iii) the page background color turns yellow and the text string "Here comes another color surprise..." pops up;
(iv) a second for loop counts to 10,000; and finally,
(v) the page background turns pink.

In practice, all I see when I go to the assignment answer page is the end result, i.e., a pink page with the aforementioned <h2>Hold on to Your Hat!</h2> header and "Here comes another color surprise..." string; at best, the yellow background of stage (iii) above is observable for a split second, whereas the white background of stage (i) is not seen at all. However, my nonobservation of stages (i) and (iii) is easily explained; even my relatively ancient computer, with its 350-MHz processor, burns through a 10,000-iteration for loop in about 35-45 milliseconds when using MSIE, as determined by:

d0 = new Date( );
/* from Netscape's Date object documentation: "The date is measured in milliseconds since midnight 01 January, 1970 UTC." */
for (i=1; i<=10000; i=i+1) { } // the braces here are necessary! d1 = new Date( ); // d1-d0 returns 35-45 when using MSIE 5.1.6; d1-d0 returns 80-85 when using Netscape 7.02 "When was Primer #24 written, and what sort of stone-age machine was Joe using at the time?" I was wondering that myself (my attempt to find a Primer #24 mirror that brings the assignment 'up to date' was unsuccessful, BTW)...anyway, it turns out that I can get the assignment answer script to cleanly separate stages (i), (iii), and (v) sometimes, not always reproducibly, with MSIE when I beef up the number of for iterations to 750,000:

for (i=1; i<=750000; i=i+1) { } // in this case, d1-d0 ≅ 2800 (2.8 seconds) Functionizing the for loops also helps; after a bit of experimentation, I find that the following code executes satisfactorily 70-80% of the time, again when using MSIE:

<body bgcolor="white" onload="count2( );">
<h2>Hold on to your hat!</h2>
<script type="text/javascript">
function count1( ) {
for (i=1; i<=750000; i=i+1) { }
document.write("Here Comes a Color Surprise!...");
document.bgColor="yellow"; }
count1( );
function count2( ) {
for (i=1; i<=750000; i=i+1) { }
document.bgColor="pink"; }
</script></body>

Curiously, the identity of the preceding (history.go(-1)) page affects the display of my modified scripts. For example, when I go directly from http://www.google.com/ to a bookmarked file whose source contains the functionized-for-loops script, I usually see stages (iii) and (v) but not stage (i), but I see all three stages when I access the file from http://www.wikipedia.org/. Perhaps someone with a detailed knowledge of Internet Explorer and its JScript engine could explain this behavior, but I am not that person.

As for Netscape:
• Regardless of any alterations that I make to Joe's answer script, Netscape 7.02 evidently insists on reading through a document and interpreting its script parts before displaying anything, and all I ever see with this version is the stage-(v) end result.
• Bizarrely, with Netscape 4.79 (yes, I still have this on my hard disk) my demo page linked above displays as desired (if more slowly than with MSIE). Go figure.

I offer no guarantee that my answer script modifications will work for you, but even if your computer is five times as fast as mine is, then you should still briefly see stages (i), (iii), and (v) at my demo page (or at least I still see them when I lower the for iteration count to 150,000 - conversely, you might try increasing the for iteration count if you don't see stages (i) and (iii)).

More generally, it seems to me that in this assignment Joe is using for loops for a time-delaying purpose for which they are not really intended, and it is in fact much easier to schedule the (i)/(iii)/(v) script stages with window.setTimeout( ) commands (I thought of using window.setTimeout( ) commands in my answer, but that seemed like 'cheating'; the whole point of the assignment, after all, is to separate the (i)/(iii)/(v) script stages via for loops). The assignment still serves as an interesting exercise, however; quite often there is considerable instructive value in dissecting problems that are inappropriate for one reason or another.

Next up: Primer #25 and while loops.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)