http://insideria.com/2009/04/51-actionscript-30-and-flex-op.html
A homework assignment I was recently given for a Java programming class involved a competition to see who could create the most optimized implementation of an interface which was provided by the instructor. It was a challenging and very fun assignment that I think the whole class enjoyed. I didn’t win the competition but still came out a winner because of my heightened interest in application optimization and performance tuning that I gained.
I’m personally a pretty big fan of coding standards and have been ribbed by many developers over some of the longer method, variable and class names that I sometimes choose. I've always leaned toward the side of programming that employs standards and frameworks . Rather than spending a ton of time digging around in compiler specs and messing with GC (Garbage Collection) for reasons of performance, tuning and optimization. I was leaving this to the seasoned programmers creating the standards and frameworks I use.
This isn’t to say I’ve never paid attention to performance and I enjoy building slow applications. It’s almost like two different worlds; the optimization world and the standards world. They don’t always agree with each other. There can sometimes be a trade off for performance over readability and organization or vice-versa. This article is meant to stand next to the Flex Best Practices articles that I authored.
While creating my concrete implementation for the homework assignment I discovered a powerful profiling engine in NetBeans. The NetBeans profiling engine helped me understand some of the memory usage and consumption of each property, method call and object instantiation in my program. This profiler in NetBeans is very similar to the one found in Flex Builder. Both are very powerful and very useful. I've been exploring the Flex Profiler in greater detail lately as well and using it to eradicate memory leaks for a real world application I’ve been refactoring to best practices lately.
The Java optimization homework has increased my interest in optimization and profiling for ActionScript 3.0 and Flex development. I've been piecing together ActionScript optimization techniques and practices from around the web for a couple years now. Some of these techniques are in opposition to what the standards dictate but most of software development is this way. You have to learn when to use some techniques and when to leave some out.
Here is a round up of ActionScript 3.0 and Flex optimization techniques and practices. I’ve scoured the web for and filtered practices and techniques that can be adopted into your application development process.
1. Avoid the new operator when creating Arrays
var a = [];
NOT:
var a = new Array();
2. Arrays are expensive to create, do so conservatively
var vanityCollection01 : Array = new Array();
var vanityCollection02 : Array = new Array();
var vanityCollection03 : Array = new Array();
var vanityCollection04 : Array = new Array();
3. Fastest way to copy an array:
var copy : Array = sourceArray.concat();
4. Setting values in Arrays is slow
employees.push( employee );
employees[2] = employee;
5. Getting values from Arrays is twice as fast as setting
var employee : Employee = employees[2];
6. Use static for properties methods that do not require an object instance
StringUtils.trim( "text with space at end " );
Class definition:
package
{
public final class StringUtils
{
public static function trim( s : String ) : String
{
var trimmed : String;
// implementation...
return trimmed;
}
}
}
7. Use const for properties that will never change throughout the lifecycle of the application
public const APPLICATION_PUBLISHER : String = "Company, Inc.";
8. Use final when no subclasses need to be created of a class
public final class StringUtils
9. Length of method/variable names doesn't matter in ActionScript 3.0 (true in other langs)
someCrazyLongMethodNameDoesntReallyImpactPerformanceTooMuch();
10. One line assignments DO NOT buy any performance (true in other langs)
var i=0; j=10; k=200;
11. No difference in memory usage between an if statement and a switch statement
if ( condition )
{
// handle condition
}
IDENTICAL MEMORY USAGE:
switch ( condition )
{
case "A":
// logic to handle case A
break;
case "B":
// logic to handle case B
break;
}
12. Rank your if statements in order of comparisons most likely to be true
if ( conditionThatHappensAlot )
{
// logic to handle frequently met condition
}
else if ( conditionThatHappensSomtimes )
{
// handle the case that happens occaisonally
}
else
{
// handle the case that doesn’t happen that often
}
13. AVM promotes int to Number during calculations inside loops (VM has been changing, from 9 to 10, so int, uint and number conversions aren't as slow as they used to be.)
14. Resolve issues of promotion, unknown, or incorrect object types
15. Use uint sparingly, it can be slow (VM has been changing, from 9 to 10, so int, uint and number conversions aren't as slow as they used to be.)
var footerHex : uint = 0x00ccff;
16. Use integers for iterations
(var i: int = 0; i < n; i++) NOT for (var i: Number = 0; i < n; i++)
17. Don't use int with decimals
var decimal : Number = 14.654;
NOT:
var decimal : int = 14.654;
18. Multiply vs. Divide: instead of 5000/1000 use: 5000*0.001
19. Locally store function values in for and while statements instead of repeatedly accessing them
for (..){ a * 180 / Math.PI; }
declare: toRadians = a*180/Math.PI; outside of the loop
20. Avoid calculations and method calls in loops
var len : int = myArray.lengh;
for (var i=0;i<len;i++){}
NOT:
for (var i=0;i< myArray.lengh;i++){ }
21. Use RegEx for validation, use string methods for searching
// postal code validation example using regular expressions
private var regEx:RegExp = /^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$/i;
private function validatePostal( event : Event ) : void
{
if( regEx.test( zipTextInput.text ) )
{
// handle invalid input case
}
}
// search a string using String methods
var string : String = "Search me";
var searchIndex : int = string.indexOf( "me" );
var search : String = string.substring( searchIndex, searchIndex + 2 );
22. Reuse objects to maintain a “memory plateau” DisplayObjects, URLLoader objects
23. Follow the Flex component model:
createChildren();
commitProperties();
updateDisplayList();
24. Only use Datagrids as a last resort (make sure you can’t implement in a regular List first)
25. Avoid Repeaters for scrollable data
26. Avoid the setStyle() method (One of the most expensive calls in the Flex framework)
27. Using too many containers dramatically reduces the performance of your application
<mx:Panel>
<mx:VBox>
<mx:HBox>
<mx:Label text="Label 1" />
<mx:VBox>
<mx:Label text="Label 2" />
</mx:VBox>
<mx:HBox>
<mx:Label text="Label 3" />
<mx:VBox>
<mx:Label text="Label 4" />
</mx:VBox>
</mx:HBox>
</mx:HBox>
</mx:VBox>
</mx:Panel>
28. You do not need to always use a container tag as the top-level tag of components Totally valid component, no top level container needed:
<mx:Image xmlns:mx="http://www.adobe.com/2006/mxml"
source="avatar.jpg" width="200" height="200" />
29. Remove unnecessary container wrappers to reduce container nesting
30. Avoid: The VBox container inside an tag, (eliminates redundancy)
<mx:Panel>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:Panel>
<mx:Panel>
<mx:VBox>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:VBox>
</mx:Panel>
31. Avoid: VBox container inside an mx:Application tag, (eliminates redundancy)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:Application>
NOT:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml>
<mx:VBox>
<mx:Label text="Label 1" />
<mx:Label text="Label 2" />
</mx:VBox>
</mx:Application>
32. Set the recycleChildren property to true to improve a Repeater object's performance (re-uses previously created children instead of creating new ones)
<mx:Script>
<![CDATA[
[Bindable]
public var repeaterData : Array = ["data 1", "data 2"];
]]>
</mx:Script>
<mx:Repeater id="repeater" dataProvider="{repeaterData}">
<mx:Label text="data item: {repeater.currentItem}"/>
</mx:Repeater>
33. Keep framerate set at 60 fps or lower
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=http://www.adobe.com/2006/mxml
frameRate="45">
</mx:Application>
34. Avoid multiple display manipulations per frame
35. Code against ENTER_FRAME events instead of Timer events
public function onEnterFrame( event : Event ) : void
{
}
private function init() : void
{
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
NOT:
public function onTimerTick( event : Event ) : void
{
}
private function init() : void
{
var timer : Timer = new Timer();
timer.start();
timer.addEventListener( TimerEvent.TIMER, onTimerTick );
}
36. To defer object creation over multiple frames use:
<mx:Container creationPolicy="queued"/>
37. Alpha = 0 is not the same as visible = false (Objects marked invisible are passed over)
loginButton.visible = false;
NOT:
loginButton.alpha = 0;