Showing posts with label Performance. Show all posts
Showing posts with label Performance. Show all posts

Saturday, November 12, 2011

Flex Error Handling with simple Example

I have recently read and heard about situations in which Flex error handling is misunderstood. In this blog entry, I'll attempt to demonstrate, with a simple example, how Flex error handling works and attempt to drive out some of the sources of confusion. To keep this entry a reasonable size, I'll focus specifically on the Flex handling of errors (synchronous) and won't address Flex handling of error events (asynchronous).

Before I get into the actual example of throwing, catching, and "handling" (printing error contents in this simple case) a synchronous error in Flex, I need to point out the significance of using the Flash Player Debugger Version. My example will demonstrate that an error will provide some information regardless of whether it is used with a regular Flash Player or a Debugger Flash Player, but the Error class's getStackTrace() method will only return a not-null value if run in a debugger version of the Flash Player.

As I explained in my blog post on the command-line fdb debugger, it makes sense to me to only be able to see the stack trace in the debugger player because you probably don't want to spill too much error information (including ugly stack traces) all over your average client's application. On the other hand, when you have debugging turned on and are running a debugger version of the Flash Player, you probably do want the ability to see the stack trace as provided by Error.getStackTrace().

Flex provides several pre-defined ActionScript-based error classes that a Flex developer can explicitly throw when appropriate and can also expect certain Flex methods to throw when the related exceptional condition is encountered. These error classes provided by Flex out of the box include ECMAScript-mandated errors and some Flash-specific errors. All errors should extend the Error class. For Java developers, extending Flex's Error class and catching thrown Flex errors (either Error or any of its children) will seem very similar to exception handling in Java. Even the try-catch-finally syntax is remarkably similar.

Let's look at some code. The following is the code listing for the simple example.






import mx.utils.ObjectUtil;

/**
* Test Flex exception handling.
*/
public function testException():void
{
try
{
intentionallyThrowException();
}
catch (error:Error)
{
stackTraceText.text = ObjectUtil.toString(error.getStackTrace());
messageText.text = error.message;
toStringText.text = error.toString();
nameText.text = error.name;
errorIdText.text = String(error.errorID);
}
finally
{
// I get called whether an exception is caught or not.
}
}

/**
* Intentionally throw an exception for use in Flex exception
* testing.
*/
public function intentionallyThrowException():void
{
throw new SyntaxError("That was some bad syntax!");
}
























A significant portion of the above code is actually comments. If you remove the explanatory comments, the code is pretty small. Either way, the code is straightforward, especially if you have written Java exception handling code before.

The example code presents key properties (ID, message, and name), a key method (getStackTrace()), and the toString() representation of an Error class in the Flex form for easy viewing. When the compiled Flex application (.swf file) is executed with a normal (non-debugger) Flash Player, the output appears as shown in the next screen snapshot:

Even without the debugger player being used, the "message" and "name" properties (the combination of which is provided by the Error's toString()) provide useful information. However, the stack trace is a null because we are not using a debugger player.

With a debugger player being used, the results are different as shown in the next screen snapshot:

Without making any changes to my code and, in fact, the only change being the use of a debugger Flash Player instead of the regular Flash Player, I now have access to the stack trace!

It is also worth mentioning here another advantage of the Flash Player Debugger version when working with errors in Flex development. The example above demonstrated a case where an error was anticipated and code was written to catch it. Flex, unlike Java but like most other languages, does not have checked exceptions/errors. This means that a developer is never required to catch a particular error. This also implies that unanticipated errors can and do get thrown. What happens to these differs depending on which Flash Player is being used. If the regular Flash Player is being used, there is usually no sign of an error condition, but often things don't work as they should either (because the underlying error is preventing something necessary from happening). With the debugger version of the Flash Player, a stack trace is automatically presented in a pop-up for any uncaught errors. Again, it makes sense that one would want this in development but would not necessarily want the average end-user with a regular Flash Player to see it.

To illustrate the uncaught error scenario, I am adding a method to the above example that calls the same method that intentionally throws the error. This second code listing also differs from the first because I made a concerted effort to rename things from Exception to Error to be more in line with Flex terminology.































When the SWF compiled from the code immediately above is executed against the regular Flash Player, there is no visual evidence of the uncaught exception in the newly added ActionScript method testWithoutErrorHandling(). However, there is a dramatic difference when using the debugger Flash Player. It places the stack trace in an pop-up as shown in the next screen snapshot.

As the above screen snapshot shows, we did not need to add any extra code to see this stack trace. Simply using the debugger Flash Player led to the unanticipated error having its stack trace displayed.

Side Note: Because of advantages such as access to the stack trace via Error.getStackTrace() call, access to the stack trace automatically when an unanticipated error is not captured, and the ability to trace statements to the fdb debugger, I recommend to anyone considering working with Flex that they use the Flash Player debugger version by default during Flex development.

The results shown above were run on SWF files compiled with mxmlc using its default options as specified in the flex-config.xml file. I now move onto looking at how tweaking one of the settings in the flex-config.xml file can affect error handling in Flex.

There is an entry in the flex-config.xml file that looks like this:


false'

Changing the "false" to "true" leads to more verbose output in the pop-up that appears for uncaught errors when run in the Flash Debugger Player as shown in the next screen snapshot. Similarly, this change leads to the same extra verbosity in the Error.getStackTrace() results. In short, the stack trace associated with an Error and available either implicitly for uncaught errors or explicitly for captured errors via the Error.getStackTrace() call, can have its level of verbosity controlled with this verbose-stacktrace setting.

If the two pop-ups are compared, it is obvious that the turning the option from "false" to "true" really did increase the stack trace verbosity. If the application is run in a regular, non-debug Flash Player, there is still no indication of an uncaught error ever occurring and null is still returned from Error.getStackTrace().

Conclusion

Flex provides error handling mechanisms that have many similar characteristics as Java exception handling, including the syntax. However, there are also some differences in the treatment of errors in ActionScript and Flex as compared to Java (such as no checked exceptions). Using a debugger version of the Flash Player for development of Flex is always a good idea, but this is particularly true when dealing with Flex error handling.

Top 10 Tips for Flex Application Performance

In general, it is good practice to maintain clean code. Not only in the sense of having properly formatted and readable code, but also code that leaves nothing behind… no memory leaks, no cpu hogs, nothing but a clean object that can be reclaimed by the GC.

Rule # 1: Clean up after yourself

1) Manage your event listeners – this message is two fold. First, you should always remove event listeners that are no longer needed. They can lead to object references that prevent the garbage collector, which equates to memory leaks, which can be very difficult to track down and detrimental to application performance. You can use weakly referenced event listeners to minimize memory leakage, but you still should explicitly clean them up when you don’t need them anymore. The second factor is that failure to remove event listeners can cause performance issues. Event handlers could be firing within your application, which you weren’t even aware of. You dispatch an event in a child component, and there could be handlers up the DOM tree (parent objects) that are also firing on the same event. If you don’t want this to happen, be explicit with your event handlers; make them handle specific event types, and get rid of them when your application doesn’t need them anymore.

2) Unload loaders – any time that you are using an object based on a loader (Image, SWFLoader, etc…), it’s a good practice to call unloadAndStop() to unload the content from the loader, and invoke the GC. This will free up valuable system resources and cpu cycles won’t be wasted if they aren’t needed. I typically even do this for static image files, to prevent memory usage from creeping up.

3) Dispose of things – I find it to be a very good practice to create “dispose()” functions in your custom components, data managers, or views that will clean up the object’s resources. The dispose() method will need to be explicitly invoked when you are finished using an object, but that dispose method will handle everything needed to clean up an object and free it’s resources. For example, stop timers, remove event listeners, unload loader objects, set variable references to null, etc… Basically, get rid of anything that could possibly cause a memory leak or eat cpu cycles behind the scenes. Yes, it takes cpu cycles to invoke a dispose method, but trust me. It is much easier and much less computationally expensive to explicitly dispose of objects, rather than burn time, computation resources, and budget tracking down leaks and performance issues.

Rule #2: If you don’t have to do it, don’t do it

Another good rule to live by is that if you don’t have to do something, then don’t do it. No, I don’t mean “don’t do your work”, or “don’t brush your teeth”. You need to do those. Instead, I mean don’t perform computationally intensive, or resource consuming actions if you don’t need to.

4) Handle collections properly – There are a few things I see all the time, and they’re always the first things to change if I see them. Collections (ArrayCollection, XMLListCollection, etc…) are helper classes that wrap primitive structures like array or xmllist. In order to help make working with those primitives easier, the collection classes do things that can be computationally expensive if you aren’t aware of them. The reason that bindings to collection work is because every time you add, remove, or update an item, events get dispatched. They also get dispatched every time you refresh a collection.

The first tip is to be conscious of collection events. If you loop over a collection and update 100,000 items, 100,000 events will get dispatched. This can cause massive performance implications, and can completely lock your application UI. If you don’t need those collection events to be dispatched, you can use the disableAutoUpdate() function to suspend collection events. Just be sure to turn them back on when you are done, or if you need them again, using the enableAutoUpdate() function.

The second, is to not use a collection if you don’t have to. If all you need is to do loop over 100,000 items, and you arne’t using data bindings, then use an array.

And the third tip on collections is only when collections are filtered using a filter function… If a filter function is applied, you don’t need to call the refresh() function every time you add a new object to the collection. This can cause performance hits, in some of the least expected places. For example, if you have a datagrid bound to a collection, and have another process which updates that collection. If there is a filter on the collection, it will automatically get filtered when you call the collection’s addItem method. Calling the refresh() method after adding an item will cause the list data of the datagrid to be invalidated, thus causing the entire datagrid to be re-validated and re-drawn. This is easily missed when optimizing, and can make drastic changes in application performance.

5) Use deferred instantiation – By default, all navigational containers within Flex (tab nav, accordion, viewstack, etc…) only create their children as they are needed. This prevents the application from creating thousands of components that aren’t needed yet, which helps keep the application running smooth, and without hogging resources or locking up. Changing the creation policy can cause big problems if you are not careful.

You should also keep deferred instantiation in mind when creating your own custom components. Don’t create child objects in the constructor. Instead, override the createChildren() method, and create them in there. This way, your components also follow deferred instantiation rules, and they don’t introduce any performance issues that can be difficult to track down.

6) Object recycling vs new objects – I’ve written about this one before, but I’ll say it again. It is often less expensive to reuse existing objects, rather than creating new ones. This goes hand-in-hand with data virtualization.

7) Don’t invalidate/destroy/re-validate your objects if nothing changed.
If you are building custom components, and someone changes a property (through a getter/setter), don’t invalidate the component properties if the incoming value didn’t change. This will cause the component to go through the full invalidation/validation lifecycle, causing properties to be re-validated/comitted, and the object to be redrawn on the display list. Only invalidate properties if something actually changed. Here is a straightforward example to demonstrate the concept:
public function set myProperty( value : Number ) : void

{

if ( _myProperty != value )

{

_myProperty = value;

propertiesChanged = true;

invalidateProperties();

dispatchEvent( new Event( "change" ) );

}

}

Rule #3: Use the language appropriately

The ActionScript language has features that enable performance… use them.

8) Dynamic/Generic vs. Typed Objects – Dynamic and generic objects certainly have their place. They are generic, flexible, can be modified with any attribute, and can be used in a wide variety of situations. However, if you have a typed object and do not need the generic qualities, use strongly typed objects. The strongly typed nature of ActionScript 3 is one of the reasons it is fast. Accessing properties of strongly typed objects is simply faster than accessing properties of generic & dynamic objects.

9) Use constants when applicable - If you have a value that does not ever change, but you reference it all the time, use a constant. Constants are accessed faster and require less overhead.

10) Use static members – Static properties and functions do not require a variable instance to be invoked or accessed. Since they don’t require an instance, it is faster to access them directly from the class, and does not require the memory necessary to instantiate the object. Utility functions, or functions that do not require attributes of a specific instance should be put into static functions.

Speaking of constants in #9… normally I suggest to make constants static. This will help you keep your memory footprint to a minimum b/c it will not need to be attached to a class instance.

All of these may seem like trivial or minor coding practices, but believe me, they can add up. In reality, it always boils down to proper coding practice, and this list highlights just a few things that you should consider when building your applications.