So far we've explored a lot of techniques and also the syntax to accomplish many goals. Inevitably, however, when you begin writing your own ActionScript, you'll encounter innumerable errors (especially at first when you are still making syntax and conceptual errors). Do not lose heart! Even experienced programmers spend a lot of time debugging (fixing broken code).
It is important that you test your product thoroughly so that you can find the bugs in the first place. This means testing in various browser brands and versions of those brands on all platforms that you intend to support. Test under different flavors of Windows and, if applicable, older versions of the Flash plug-in, which you can find at:
http://www.macromedia.com/support/flash/ts/documents/oldplayers.htm
A discussion of testing and quality assurance (QA) is beyond the scope of this book. Suffice to say that you should have a testing and QA process in place and a bug report form on which you can receive reports with sufficient detail (such as the platform, browser version, Flash plug-in version, and reproducible steps) for you to reproduce the error, which is the first step toward fixing it.
Debugging is an essential part of programming and what sets great programmers apart from average ones. Beginners are often happy if a bug that was seen earlier inexplicably disappears. Experienced programmers know that the bug will undoubtedly resurface at the most inopportune time, and although it is intermittent (perhaps especially so), it warrants further investigation. On the other hand, inexperienced programmers tend to shy away from error messages or be unnerved by obvious errors, whereas skilled programmers rely heavily on error messages and know that easily reproducible errors are the easiest kind to fix.
Successful debugging requires logical, disciplined investigative skills and a decent understanding of troubleshooting tools. In this chapter, we'll briefly consider the basics of debugging tools and some general techniques for solving code problems. Remember that debugging is characterized by the systematic challenging of our assumptions. Any given problem is often caused by some other problem upstream (i.e., the disease). We'll use the debugging tools to investigate whether things are in fact operating as designed, and that will lead to an understanding and resolution of the manifest bug (i.e., the symptom).
ActionScript comes equipped with the following debugging tools:
The trace( ) function
The List Variables command
The List Objects command
The Bandwidth Profiler
The Debugger
All of these tools are used in Test Movie mode. To enter Test Movie mode, we export a movie from the authoring tool using Control Test Movie.
In addition to these formal debugging tools, Flash also sends error messages to the Output window when a movie is exported or Check Syntax is performed. (Check Syntax is a command listed under the arrow button in the top right of the Actions panel.) Error messages often identify the exact cause of a problem down to the problematic line number in a block of source code. Comprehensive explanations for the various error messages are provided in Macromedia's ActionScript Reference Guide.
Note that not all bugs cause error messages. For example, a calculation that yields the wrong result is a bug even if it doesn't crash your browser. Also note that there are two types of error messages, so-called compile-time error messages that occur when you try to export your scripts and so-called runtime error messages that don't occur until you run your Flash movie and reach the point that causes the error. Compile-time errors indicate some sort of syntax problem such as a missing parenthesis or unclosed quotation. Refer to Part III, "Language Reference", for the exact syntax needed for each command, and refer to Chapter 14, "Lexical Structure", for an explanation of proper ActionScript syntax.
Runtime errors can take a wide variety of forms and may not indicate a problem with the current code under examination but rather may be caused by using the incorrect result of an earlier operation. For example, suppose you try to use the values received back from a loadVariables( ) command sent to a web server. If the Perl script responding to the command didn't supply the correct data in the correct format, you need to correct the Perl script. Your Flash script may be perfectly correct and yet fail because it received incorrect input.
Which brings up an important technique -- defensive programming. You can avoid a lot of errors and potential errors by always checking for potential problematic conditions, which is known as error checking (or sometimes data validation if it pertains to user input). For example, before trying to display the questions of a quiz, you might check that those questions loaded properly. You might also check each question to be sure it's in the correct format for display. If the provided data was improperly entered, you should display an appropriate error message that allows the programmer or the user to take corrective action.
In ActionScript, one of the most effective tools for identifying the source of a bug is also one of the simplest -- the trace( ) function. As we've seen throughout this book, trace( ) sends the value of an expression to the Output window in Test Movie mode. For example, if we add the following code to a movie:
trace("hello world");
the text "hello world" appears in the Output window. Similarly, here we trace( ) the value of a variable:
var x = 5; trace(x); // Displays 5 in the Output window
Using trace( ) we may check the status of variables, properties, and objects, and we may track the progression of our code. Often by confirming the result of each operation in a script, we can figure out where a problem lies. For example, suppose a function is supposed to return a value but we find, using the trace( ) command, that the return value is undefined (i.e., it prints out as nothing in the Output window). We'd know that we have to examine the function in more detail and make sure that it is properly using a return command to pass back a meaningful value.
When a movie is running in Test Movie mode, we can check the value of current variables defined in the movie via the Debug List Variables command. List Variables tells us the name and location of all the variables currently active in our movie and also reports their values. Because functions and movie clips are stored in variables, the List Variables command also shows us the functions and movie clips of a movie.
Example 19-1 shows sample output from List Variables. Notice that the variable rate is shown as declared but undefined. This subtlety is often difficult to detect with trace( ) because trace( ) converts the value undefined to the empty string ("").
Level #0: Variable _level0.$version = "WIN 5,0,30,0" Variable _level0.calcDist = [function] Variable _level0.deltaX = 194 Variable _level0.deltaY = 179 Variable _level0.rate = undefined Variable _level0.dist = 264 Movie Clip: Target="_level0.clip1" Movie Clip: Target="_level0.clip2"
Note that both trace( ) and the List Variables command give only a snapshot in time. Often, you'll want to monitor the value of a variable over time or check it repeatedly. The Debugger (discussed later) allows you to track the value of a variable as it changes.
The List Objects command produces a catalog of text, shapes, graphics, and movie clips defined in a movie. To execute it, select Debug List Objects while in Test Movie mode. Note that List Objects does not include a list of data objects (instances of a class) in a program; those are reported by List Variables.
Example 19-2 shows some sample output from List Objects. Notice that editable text fields are clearly labeled and that automatically named movie clip instances are revealed (e.g., _level0.instance1).
Level #0: Frame=1 Shape: Text: Value = "variables functions clip events startDrag stopDrag Math" Text: Value = "this movie demonstrates a little math, variables, movie clip events" Text: Value = "draggable distance" Text: Value = "calculator" Movie Clip: Frame=1 Target="_level0.instance1" Shape: Text: Value = "distance between clipstotal:horizontal:vertical:" Edit Text: Variable=_level0.dist Text="222" Edit Text: Variable=_level0.deltaX Text="174" Edit Text: Variable=_level0.deltaY Text="138" Movie Clip: Frame=1 Target="_level0.obj1" Shape: Movie Clip: Frame=1 Target="_level0.obj2" Shape:
Again, List Objects provides only a snapshot in time. You need to run it again to get the current value of objects whenever they may have changed.
The Bandwidth Profiler is used to simulate movie download at various modem speeds. Using the Bandwidth Profiler, we may gauge the performance of a movie, test preloading code, and track the position of the main movie's playhead during movie playback. Here's how to turn the Bandwidth Profiler on:
While in Test Movie mode, select View Bandwidth Profiler.
Under the Debug menu, select the desired download rate.
To simulate the download of a movie at that rate, select View Show Streaming.
There are many things that can affect Flash performance, such as the assets in use and the rendering demands on the Player. For example, using large bitmaps, rendering complex shapes with many curves, and excessive use of alpha channels can all degrade performance. Asset downloading and rendering times usually dwarf the bandwidth and processor time required for ActionScript to execute. That said, ActionScript is generally much slower than compiled languages such as C.
From an ActionScript perspective, the most time-consuming operations are those that either must wait for data to be uploaded or downloaded or those that are performed repetitively (such as examining a large array).
WARNING
Displaying items in the Output window is very slow compared to "invisible" operations in ActionScript. If a simple movie seems excessively choppy, try disabling all trace( ) statements, or play the movie outside Test Movie mode.
A discussion of writing optimized code is beyond the scope of this book, but some quick tips should suffice:
Don't perform an operation repeatedly within a loop if it can be performed once outside of a loop with no loss of functionality.
Don't wait in a loop for some event to occur. The event may take a long time or may never occur, causing your performance to slow or your application to lock up entirely. Instead, rely on event handlers, such as on (load) to be triggered when an event occurs or completes.
Generalize your code wherever possible (perhaps even use Smart Clips to do so). This reduces the size of the code that needs to be downloaded. For example, instead of writing two nearly identical routines that are each 5 KB long, you can save 5 KB by writing one generalized routine and calling it twice with different parameters. (Generalizing code is explained in Chapter 9, "Functions", and Smart Clips are explained in Chapter 16, "ActionScript Authoring Environment").
If you're using the Flash 5 Player and optimized ActionScript performance is critical to your project, try using old-style Flash 4 syntax instead of newer techniques. In Flash 5, certain operations are faster when phrased with Flash 4 syntax. For example, Flash 4's substring( ) function is faster than Flash 5's substring( ) and substr( ) methods, and Flash 4's Tell Target is faster than Flash 5's dot notation.
Export your movies without trace( ) statements by selecting Publish Settings Flash Options Omit Trace Actions.
Remember that removing and reattaching a clip is more costly than moving an existing one; reuse your movie assets whenever possible.
For a list of general Flash optimization techniques, see http://www.macromedia.com/support/flash/publishexport/stream_optimize/stream_optimize.html.
The Debugger is a highly useful tool that gives us organized access to the values of properties, objects, and variables in a movie and even allows us to change variable values at runtime.
To enable the Debugger, select Control Debug Movie in the Flash authoring tool (not in Test Movie mode). You may also use the Debugger in a web browser, provided that:
The movie being viewed was originally exported with debugging permitted.
The Player being used to view the movie is a debugging Player.
The Flash authoring tool is running when you attempt to debug.
To export a movie with in-browser debugging permitted, select File Publish Settings Flash Debugging Permitted, then optionally provide a password to prevent prying eyes from snooping around your code. To install a debugging Player in your browser, use the installers provided in the /Players/Debug / folder where you installed Flash on your hard drive. To enable debugging while viewing a movie, right-click in Windows (Ctrl-click on Macintosh) on the movie and select Debugger.
TIP
Not all versions of the Flash Player have a corresponding debugging Player. Check Macromedia's support site for the newest versions of the debugging Player,http://www.macromedia.com/support/flash.
The top half of the Debugger (the Display List) shows the movie clip hierarchy of the movie. To inspect the properties and variables of a specific movie clip, select it in the Display List. The bottom half of the Debugger contains three tabs, Properties, Variables, and Watch, which update dynamically to show the properties and variables for the selected clip. To set the value of any property or variable, double-click its value and enter the new data. To single out one or more items for convenient scrutiny, select them in the Properties or Variables tab, then choose Add Watch from the arrow button in the upper-right corner of the Debugger. All "watched" variables are added to the Watch tab (this lets us view variables in different movie clips simultaneously).
For more information about the mechanics of using the Flash Debugger, consult Macromedia's thorough documentation under "Troubleshooting ActionScript" in the ActionScript Reference Guide. If you've lost your Reference Guide, remember that it's available on Macromedia's web site at http://www.macromedia.com/support/flash and also under the Help menu in the Flash authoring tool.
Copyright © 2002 O'Reilly & Associates. All rights reserved.