Copyright © 2003 O'Reilly Media, Inc. All Rights Reserved.
Flash Remoting: The Definitive Guide
By Tom Muck
September 2003
ISBN: 0-596-00401-X
http://www.oreilly.com/catalog/flashremoting/
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

Most of your performance problems are going to be the result of a repeated operation that is not optimized. A nonoptimized piece of code that executes one time is not likely to have an impact on an application; however a nonoptimized piece of code that executes 1,000 times in a loop is going to kill the performance. For that reason, any code that is executed repeatedly, such as an onEnterFrame( ) handler or a for loop is a potential bottleneck.

Macromedia improved the performance of the Flash Remoting classes in the first updater, available at http://www.macromedia.com. One technique that was originally used throughout the Flash Remoting classes involves initializing a for loop in a nonoptimized way. In standard ECMA scripting, the middle section of the for loop (the condition in the for(variable; condition; update) construct) is evaluated each time the loop executes. For that reason, a static value should be used whenever possible.

Bad:

for (var i = 0; i < this.getLength( ); i++) {
 // Do something
}

Good:

var tempLength = this.getLength( );
for (var i = 0; i < tempLength; i++) {
 // Do something
}

However, counting down is even faster:

var tempLength = this.getLength( )-1;
for (var i = tempLength; i >= 0; i--) {
 // Do something
}

Optimizing a loop's condition expression is only the first step. Code within the loop should be optimized whenever possible, for this is where your application performance is going to suffer the worst. This is especially true if you are populating a UI component, such as a Tree. If a piece of code that takes 1 millisecond to execute can be removed from a loop that is repeated 1,000 times, you'll save 1 second (which can make an application feel much more responsive). The most basic technique is moving outside the loop any operation that doesn't need to be performed repeatedly. Consider the following two cases. In this case, the string is initialized to "Hello Tom!" within the loop:

for (var i = 0; i <= 10; i++) {
 myString = "Hello Tom!";
 trace(myString.substring(0, i));
}

In this case, the string is initialized outside the loop:

myString = "Hello Tom!";
for (var i = 0; i <= 10; i++) {
 trace(myString.substring(0, i));
}

In the first case, the string is initialized repeatedly, even though its value never changes. The second loop will execute faster (about 1.8 milliseconds versus 2 milliseconds). You might look for other ways to optimize the code. For example, the trace( ) statement, because it displays text in the Output window, might slow things down. Here, we accumulate all the text in a variable, outputString, and display it once, rather than executing the trace( ) statement repeatedly:

myString = "Hello Tom!";
outputString = "";
for (var i = 0; i < 10; i++) {
 outputString += myString.substring(0, i) + newline;
}
trace(outputString);

Surprise! This version takes an average of 2.4 milliseconds and is therefore slower than the trace( ) version. It turns out that string concatenation is a more expensive operation than tracing the text in the Output window.

Loops should also be terminated (broken out of) as soon as possible. Take the following piece of code as an example:

var temp = myArray.length;
for (var i=0; i < temp; i++) {
 if (findItem(myArray, myItem))
 found = true;
}
trace("found it!");

The preceding example sets a flag when a specific item has been found in the array. The problem is that the loop continues even after the item has been found. This is wasteful, especially in a recursive loop that might be populating a UI component. A better solution is to break out of the loop as soon as the item is found:

var temp = a.length;
for (var i=0; i < temp; i++) {
 if (findItem(a[i], "50")) {
 found = true;
 break;
 }
}
trace("found it!");

A loop like this will run an average of 50% faster, because an item might be found at the beginning of the loop or the end of the loop but the average will be somewhere in the middle. The loop is ended as soon as the item is found.

TIP: The preceding techniques apply equally well to any code that is executed repeatedly. For example, don't initialize data within an event handler that is called repeatedly. Initialize it once outside the event handler and refer to it as needed. Likewise, once an event handler is no longer needed, you should cease executing it. For example, if you've added a listener with addListener( ), you can remove it with removeListener( ) when it is no longer needed.