12.4 Component Use

Components are one of the
cornerstones of Rich Internet Application (RIA) development using
Flash and Flash Remoting. Components make it easy to create rich
interfaces, but they can also be responsible for an application
getting bogged down with poor performance. Many of the Macromedia
user interface components are very code-intensive when it comes to
doing things like populating the component, sorting, and adding data.
You should be conservative in your use of client-side code when
dealing with components. The DataGrid component, for example, can
utilize 90-100% of the end user's system resources
while being populated?from a remote service or local data.

The Flash 2004 component architecture is optimized for applications
that use five or six components; the shared library that Flash 2004
components require adds more file size than is justified by using
only one or two components.

12.4.1 Component Speed

The speed of a component is often
dependent on the type of code you are
utilizing. What looks more efficient to the ActionScript programmer
is often slower in execution. If you're in doubt
about the speed of a particular section of code, you can
time it using the Date( ) object. The code in
Example 12-2 is a CodeTimer
object, which can be used to time the execution of sections of code.

The preceding example tests the speed of the
DataGlue.bindFormatStrings( ) method. The
example recordset that I tested yielded an average result of 10
milliseconds. The following code shows the time taken to manually
populate the same ComboBox with the same recordset using an index
loop:

The third example is less verbose and looks like it is more
efficient, but it results in an elapsed time of 90
milliseconds?9 times slower than the first
example?showing the efficiency of the
DataGlue class. Looks are deceiving sometimes
when coding, as this example demonstrates. It's best
to not simply take the code at face value; measure your
code's execution time and try different things to
get the best possible results.

Shaving 80 milliseconds off the data-loading operation for one
ComboBox can have a dramatic impact in the end
user's experience if you have many user interface
elements and can optimize some of them in similar ways. 80
milliseconds might not seem like a lot, but when
you're dealing with a Flash interface it is wise to
conserve where you can, to balance the initial load time of the
movie, which might run into several seconds. 10 or 20 interface
elements can increase this delay by 1 or 2 seconds for the user.
Every little bit of optimization helps to improve the user
experience.

Here is a simple technique for testing performance. When
you're testing a brief operation, it may be so fast
that you can't get an accurate measure of the time
it takes. Furthermore, if an operation is performed hundreds or
thousands of times during your program execution, the execution time
may vary, and it isn't practical to add up the times
of each execution manually. You can add a
for...in loop to execute an operation, say, 100
times to give you a more accurate picture of the time required for
execution. Here is the new code (additions shown in bold):

Don't forget to take the average time, and
don't forget to remove the
for...in loop when you're done
testing (you can comment out the testing code so that it is easy to
reinstate if you want to test it again later). Be sure to test the
operations that you are trying to optimize. How would the timing
differ if the call to getColumnNames( ) were
moved outside the second loop? Refer to
"Looping" later in this chapter for
hints on optimizing loop performance.

You can get much more elaborate with timing, but this simple example
gives you the basic technique. Timing your code is very important
when dealing with Flash Remoting or Flash interfaces in general.
Sometimes, a call to the remote database will be quicker than trying
to manipulate results on the client. Also, sometimes there are
sections of code that execute too slowly in ActionScript and can be
moved to the server.

12.4.2 Data Loading

Frequently, when building data-driven Flash interfaces, you test with
a small amount of data with the knowledge that your application will
grow in the future with more back-end data. The Flash UI components
can generally handle a small amount of data, but when you start
feeding thousands of records into them they start slowing down
dramatically. How do you test with large amounts of sample data if
the data doesn't exist yet?

One way is to use a
temporary SQL statement in your
server-side service that returns a lot more rows than your test data
actually contains, by forcing a cross join on another table. A
cross join gives you a result that contains
every combination of rows of data from the joined tables. In other
words, each row in the first table is joined to every row in the
second table, giving you a huge resultset. A cross join has limited
use in everyday data retrieval but is especially handy when
you're testing application interfaces. Consider the
following query on the Northwind database:

SELECT c.CategoryID, c.CategoryName
FROM Categories c

The query returns about eight rows of data. If you were to time this
data being rendered into a ComboBox or DataGrid, you would not be
able to discern any noticeable speed problem. Change the query to
cross join the Products table:

SELECT c.CategoryID, c.CategoryName
FROM Categories c, products

Now the query returns over 600 rows by joining the
Products table and returning a complete set of
data from the Categories table for each row of
data in the Products table. The fields that you
are retrieving are the same as the fields in the first example, but
they are duplicated many times. This gives you a better idea of what
your final application will be able to handle and gives you a more
accurate picture of where your bottlenecks are. (It also gives you a
chance to test your screen layouts to see if they accommodate large
recordsets and test your logic for pageable recordsets, if
applicable.)

UI components can greatly speed up the development process, but they
can also be a performance bottleneck if the code that uses the
component is not optimized.