Chapter 4. Exploring the Benefits of Using ActionScript 3.0

It has been said, and generally agreed, that in spite of how funny it would make a person look, two heads are better than one. The point of this adage, of course, is that collaboration can be a remarkably productive venture. Flash Player 10 promotes this ideal thanks to its two virtual machines, the software modules inside Flash Player that execute ActionScript programs. Until Flash Player 9, only a single virtual machine was necessary. It handled (and still handles) everything code-related from the very beginnings of ActionScript to the formal object-oriented programming (OOP) paradigm introduced with ActionScript 2.0. The architectural changes and improvements introduced with ActionScript 3.0, however, were substantial enough in Flash Player 9 to warrant a new virtual machine specifically optimized for the new language.

This new module, named ActionScript Virtual Machine 2 (AVM2), works independently of the previous player codebase. It was unveiled in a prerelease version of Flash Player 9, originally slated as Flash Player 8.5. (There was no commercial release of Flash Player 8.5; in the final public release, its version number shipped as 9.) Legacy support is still handled by the previous codebase, now renamed ActionScript Virtual Machine 1 (AVM1) and remains as a companion module inside Flash Players 9 and 10 to support backward compatibility. Meanwhile, AVM2 ushers ActionScript 3.0 into an arena of increased performance, efficiency, and an internal consistency that makes the language easier for newcomers to learn. In this way, both old and new code are able to function with maximum efficiency and performance.

In addition to benefiting from two heads, so to speak, Flash Player 10 encourages another nuance on the concept of collaboration: that of adherence to standards. Because other Flash Platform development tools rely on the same ECMAScript specification as Flash CS4, your work in ActionScript 3.0 leads directly to portability among other Adobe technologies, such as Flex and Adobe Integrated Runtime (AIR), formerly codenamed Apollo. Learn ActionScript 3.0 in terms of the Flash authoring tool, and you already have a leg up on building online and desktop-based Rich Internet Applications (RIAs) and occasionally connected desktop applications.

Performance

In Adobe benchmarks, ActionScript 3.0 has been shown to increase application performance by an order of magnitude. This means that even complex programs can potentially execute with 10 times the speed and efficiency of ActionScript 2.0. That’s the sort of impressiveness that rivals a juggler with flaming bowling pins—who is also spinning plates, while riding a unicycle on a tightrope with no net. To be sure, some of this improvement results from enhancements to the Flash Player runtime itself, from successively better rendering with each release, the advent of bitmap caching in Flash Player 8, and hardware acceleration in Flash Player 9.0.115.0. Ultimately, though, performance depends on how well your code is written, on adherence to recommended best practices, and the boost of being executed on AVM2.

In early 2005, a participant in the Flash ActionScript support forum posed a question about using ActionScript to render something called the Mandelbrot set, which is one of the most popular examples of a series of infinitely complex geometric shapes called fractals. Chances are good you’ve seen the Mandelbrot set depicted on progressive rock album covers, as the underlying mechanism for computer-generated (CG) effects like realistic mountain terrains, or even as the printed pattern on a handful of bowties at a programming convention. The initial view of this geometric set, seen in Figure 4-1, is defined by a complicated mathematical formula. This trait makes it a good candidate for showcasing the speed increases of ActionScript 3.0, as the code discussed in 2005 can be compared side by side with a modern interpretation.

In fact, you can re-create a version of the original SWF file yourself and evaluate its performance against an ActionScript 3.0 version on your own computer.

The Mandelbrot set
Figure 4-1. The Mandelbrot set
  1. Create a new ActionScript 2.0 FLA file. Use the Property inspector to set the document’s dimensions to 340 pixels by 240 pixels and the background color to #000000 (black). Type the following code into frame 1 of a script layer:

    var startTime:Number = getTimer();
    
    var image:MovieClip = this.createEmptyMovieClip("mcImage", 0);
    image._x = 240;
    image._y = 120;
    
    var colors:Array = new Array(
        0x000000, 0x0E0E0E, 0x1C1C1C, 0x2A2A2A, 0x383838,
        0x464646, 0x555555, 0x636363, 0x717171, 0x7F7F7F,
        0x8D8D8D, 0xB9B9B9, 0xAAAAAA, 0xB8B8B8, 0xC6C6C6,
        0xD4D4D4, 0xE2E2E2, 0xF0F0F0, 0xFFFFFF
    );
    var k:Number = −120;
    var zArr:Array = new Array();
    
    var myTimer:Number = setInterval(drawLine, 1);

    This step sets up a startTime variable, which metaphorically clicks a stopwatch into action. This variable is compared to the getTimer() function again at the end, which then displays total elapsed seconds. The image variable holds a reference to a movie clip, which is used as a canvas on which the Drawing API plots a series of line segments that represent the Mandelbrot set. The colors variable points to an array of color values used during the drawing, k and zArr are used in the fractal calculation, and myTimer is eventually used to halt the repeated triggering of a custom drawLine() function, as looped once every millisecond by the setInterval() function.

  2. Next comes the drawLine() function, which is the brain of the whole operation. Type the following code after the existing ActionScript code:

    function drawLine():Void {
        var j:Number = 0;
        var x:Number = 0;
        var y:Number = 0;
        var n:Number = 0;
        var zAbs:Number = 0;
        for (j = −240; j <= 100; j++) {
            x = 0;
            y = 0;
            n = 0;
            do {
                n++;
                zArr = f(x, y, j / 100, k / 100);
                x = zArr[0];
                y = zArr[1];
                zAbs = zArr[2];
                if (n >= 20) {
                    break;
                }
            } while (zAbs <= 4);
            if (zAbs > 4) {
                image.lineStyle(1, colors[n], 100);
                image.moveTo(j, k - 1);
                image.lineTo(j, k);
            }
        }
        k++;
        if (k >= 0) {
            clearInterval(myTimer);
            duplicate();
        }
    }

    For the sake of this demonstration, it doesn’t matter if the Mandelbrot formula seems clear as mud. Just count on it that the magic happens inside the do..while statement, one of whose lines calls a custom f() function. The line segments are drawn by the calls to lineStyle(), moveTo(), and lineTo(), and the final if statement decides when to stop the setInterval() loop by calling clearInterval(), then completing the mirror image of the drawing with a call to the custom duplicate() function.

  3. Here are the final short blocks of code, the f() and duplicate() functions. Type the following code after the existing ActionScript code. Note that the last line of the duplicate() function uses trace() to report the elapsed time to the Output panel.

    function f(x:Number, y:Number, a:Number, b:Number):Array {
        var rPart:Number = x * x - y * y + a;
        var iPart:Number = 2 * x * y + b;
        return new Array(rPart, iPart, rPart * rPart + iPart * iPart);
    }
    function duplicate():Void {
        var flip:MovieClip = image.duplicateMovieClip("mcFlip", 1);
        flip._yscale = −100;
        flip._y -= 2;
        trace((getTimer() - startTime) / 1000);
    }
  4. Select Control→Test Movie to see your handiwork (Figure 4-2).

    Special thanks to Keith Gladstien, PhD, MD (http://www.kglad.com/), for permission to reprint a version of his code in this book. See Keith’s website for additional exploration of the Mandelbrot set in Flash.

An ActionScript 2.0 rendering of the Mandelbrot set
Figure 4-2. An ActionScript 2.0 rendering of the Mandelbrot set

Your own performance results may vary, depending on your computer’s power and speed. You may even want to test repeatedly and take an average of elapsed times, remembering that results will vary for individual users who view your published content. You’ll clearly see the sequential improvement when you configure the publish settings for this FLA file among various versions of Flash Player (File→Publish Settings→Flash→Version) Table 4-1 shows the averaged results of one such series of tests.

Table 4-1. Speed of Mandelbrot set as rendered in various versions of Flash Player

Flash Player version

ActionScript version

Elapsed time (in seconds)

Flash Player 6

ActionScript 2.0

21.847

Flash Player 7

ActionScript 2.0

15.225

Flash Player 8

ActionScript 2.0

13.729

Flash Player 9

ActionScript 2.0

10.338

Flash Player 9

ActionScript 3.0

2.853

Flash Player 10

ActionScript 2.0

15.557 *

Flash Player 10

ActionScript 3.0

6.387 *

* At the time of writing, Flash Player 10 actually performed more slowly than Flash Player 9. This should be addressed before Flash is publicly released.

Updating the Code to ActionScript 3.0

To experience the Mandelbrot set on your own in a matter of 2 to 3 seconds, save your current file as MandelbrotAS3.fla, and then complete the following steps. Great care has been taken to maintain the overall structure of this code, so that it parallels the ActionScript 2.0 version approximately line for line.

  1. Configure the FLA file’s publish settings for Flash Player 9 or 10 (File→Publish Settings→Flash→Version), and then change the ActionScript version to ActionScript 3.0.

  2. Update the existing code as follows (changes in are bold):

    var startTime:int = getTimer();
    
    var image:Sprite = new Sprite();
    image.x = 240;
    image.y = 120;
    addChild(image);
    
    var colors:Array = new Array(
        0x000000, 0x0E0E0E, 0x1C1C1C, 0x2A2A2A, 0x383838,
        0x464646, 0x555555, 0x636363, 0x717171, 0x7F7F7F,
        0x8D8D8D, 0xB9B9B9, 0xAAAAAA, 0xB8B8B8, 0xC6C6C6,
        0xD4D4D4, 0xE2E2E2, 0xF0F0F0, 0xFFFFFF
    );
    var k:int = −120;
    var zArr:Array = new Array();
    
    var myTimer:Timer = new Timer(1, 0);
    myTimer.addEventListener(TimerEvent.TIMER, drawLine);
    myTimer.start();

    This time, the int data type is used in cases where numerical values are integers, simply because int values consume a smaller memory footprint than Number values. Similarly, image is set to an instance of the Sprite class, rather than MovieClip, because Sprite is perfectly adequate—it supports the necessary Drawing API—and it’s the smaller data type. In this case, the timer mechanism is an instance of the Timer class.

  3. Here’s the updated version of the drawLine() function. Update the existing function to look like this:

    function drawLine(evt:TimerEvent):void {
        var j:int = 0;
        var x:Number = 0;
        var y:Number = 0;
        var n:int = 0;
        var zAbs:int = 0;
        for (j = −240; j <= 100; j++) {
            x = 0;
            y = 0;
            n = 0;
            do {
                n++;
                zArr = f(x, y, j / 100, k / 100);
                x = zArr[0];
                y = zArr[1];
                zAbs = zArr[2];
                if (n >= 20) {
                    break;
                }
            } while (zAbs <= 4);
            if (zAbs > 4) {
                image.graphics.lineStyle(1, colors[n], 100);
                image.graphics.moveTo(j, k - 1);
                image.graphics.lineTo(j, k);
            }
        }
        k++;
        if (k >= 0) {
            myTimer.stop();
            duplicate();
        }
    }

    Not a whole lot changes, as you can see. The function now accepts a parameter, as required by the TimerEvent class, and its return value is changed from Void to the lowercase void. Appropriate Number types are changed to int, and the Drawing API is now routed through a Graphics instance, as referenced by the Sprite.graphics property. Rather than clearInterval(), the timer is halted by way of the Timer.stop() method.

  4. Finally, here are the ActionScript 3.0 versions of the f() and duplicate() functions. Update the last blocks of code to look like this:

    function f(x:Number, y:Number, a:Number, b:Number):Array {
        var rPart:Number = x * x - y * y + a;
        var iPart:Number = 2 * x * y + b;
        return new Array(rPart, iPart, rPart * rPart + iPart * iPart);
    }
    function duplicate():void {
        var bmpData:BitmapData = new BitmapData(340, 120, true, 0x000000);
        var mat:Matrix = new Matrix(1, 0, 0, 1, 240, 120);
        bmpData.draw(image, mat);
        var bmp:Bitmap = new Bitmap(bmpData);
        bmp.scaleY = −1;
        bmp.y = 238;
        addChild(bmp);
        swapChildren(bmp, image);
        trace((getTimer() - startTime) / 1000);
    }

    The f() function doesn’t change at all. Since ActionScript 3.0 no longer supports the equivalent of MovieClip.duplicateMovieClip(), the duplicate() function requires a few more lines than its ActionScript 2.0 counterpart. Here, the BitmapData class is used to take a snapshot of the pixels drawn into the image sprite. These pixels are drawn into a Bitmap object, and then flipped to provide the mirror image. Because the line segments are drawn into the upper-left quadrant of the sprite—that is, left of 0 in the x-axis and above 0 in the y-axis—a matrix object is used to reposition the pixels into the lower-right quadrant (240 pixels over and 120 pixels down).

  5. Select Control→Test Movie to see the increased rendering speed. As an added bonus, note that rendering occurs even more quickly when the image sprite is added to the display list only after the Mandelbrot calculations are made. Add two slashes to line 6 of Step 2 to comment it out:

    var image:Sprite = new Sprite();
    image.x = 240;
    image.y = 120;
    //addChild(image);

    and then insert the same line into the duplicate() function of Step 4.

    function duplicate():void {
        var bmpData:BitmapData = new BitmapData(340, 120);
        var mat:Matrix = new Matrix(1, 0, 0, 1, 240, 120);
        bmpData.draw(image, mat);
        var bmp:Bitmap = new Bitmap(bmpData);
        bmp.scaleY = −1;
        bmp.y = 238;
        addChild(image);
        addChild(bmp);
        swapChildren(bmp, image);
        trace((getTimer() - startTime) / 1000);
    }

    This step can shave off an additional second from the total elapsed time. Thanks again to Keith Gladstien, PhD, MD (http://www.kglad.com/) for input.

Efficiency

Imagine a warehouse with numerous and greatly varied products: everything from Fabergé eggs to collectible trading cards to garden rakes. In order to make shipping very easy, the warehouse manager has stocked a limited range of cardboard box sizes; in fact, all their dimensions are the same, one size fits all. As hoped for, everything is indeed easy to pack. The rakes fit into the boxes just fine, and so do the eggs and cards—it’s just that anything smaller than a rake also needs several bucketsful of Styrofoam peanuts. For small shipments, this arrangement isn’t so bad, but the trading cards happen to belong to a collectible franchise named Pokémon. One of these days—and the phenomenon will seem to explode overnight—several thousand customers are going to order individually wrapped packs of cards within the span of one week. When that happens, a vein will start to throb on the manager’s forehead. Obviously, the packaging for these cards will take up more room than necessary—considerably more—and it may not be possible to fit all the required boxes on the shipping dock.

Thanks mainly to the addition of runtime types in ActionScript 3.0, Flash Players 9 and 10 can generally avoid this sort of scenario. To continue the somewhat loose analogy, you can think of runtime types as a well-organized assortment of custom-fitted cardboard boxes. Because the boxes aren’t any larger than they need to be, storing them becomes a relatively efficient endeavor. In the real world, AVM2 is capable of requesting, or allocating, only the system memory it needs to create the objects called for by the various classes used in your code. Not only that, but the hierarchy of native ActionScript 3.0 classes has been considerably reorganized to take better advantage of a tiered system of complexity.

A quick look at the MovieClip class illustrates this principle, though the same notion applies to most other ActionScript 3.0 classes. First, consider the ActionScript 2.0 implementation of MovieClip. Consulting the ActionScript 2.0 Language Reference in the onboard documentation, you’ll find that the family tree for the MovieClip class is remarkably small. This class inherits from the Object class alone (Figure 4-3), which is the base class upon which all classes are established.

In ActionScript 2.0, the MovieClip class isn’t compartmentalized
Figure 4-3. In ActionScript 2.0, the MovieClip class isn’t compartmentalized

This characteristic means the ActionScript 2.0 version of the MovieClip class carries practically all its own baggage. As often as not, this makes it heavier than it needs to be from the standpoint of system resources. If you want a visual object whose movement you can program around the stage, MovieClip is generally the most appropriate choice in ActionScript 2.0. All you really need for this sort of movement is a pair of properties that relate to the movie clip’s x and y coordinates. The ActionScript 2.0 MovieClip class delivers the _x and _y properties right to your fingertips—but you also get a number of properties you don’t really need in this situation, such as _currentframe and _totalframes (you won’t be using the movie clip’s timeline), in addition to timeline-related methods like play(), stop(), gotoAndPlay(), and so on. Even worse, the ActionScript 2.0 version of MovieClip includes a method for loading external assets (loadMovie()), and several more for drawing shapes (lineStyle(), moveTo(), lineTo(), curveTo(), and others). These additional class members add to the overall weight of every MovieClip instance, even if you don’t use them.

In ActionScript 3.0, the MovieClip class acquires most of its functionality from the Sprite class (Figure 4-4). In fact, movie clips are sprites; they’re just sprites with timelines. In turn, the Sprite class inherits most of its functionality from DisplayObjectContainer, which inherits most of its features from InteractiveObject, then DisplayObject, EventDispatcher, and finally Object—each type getting progressively simpler toward the parent side and taking up a smaller footprint of system memory.

In ActionScript 3.0, the efficiently tiered family tree of the MovieClip class lets you control the size of the object you need
Figure 4-4. In ActionScript 3.0, the efficiently tiered family tree of the MovieClip class lets you control the size of the object you need

If you don’t need the overhead of a timeline, use Sprite for your programmatic animation. It has x and y properties, but isn’t encumbered by currentFrame or totalFrames properties, nor by the aforementioned timeline- or drawing-related methods. The Sprite class still lets you draw shapes—which means the ActionScript 3.0 MovieClip class does as well—but this set of functionality is deferred to the new Graphics class, and is associated with a given sprite or movie clip by way of its graphics property. Loading duties are separated altogether, and are the new Loader class’s responsibility.

By strongly typing your variables and function return values in ActionScript 3.0, you give explicit instructions to the compiler to pack its goods into the sort of cardboard boxes that fit like a glove. Strong typing requires nothing more than a colon (:) and data type name.

var intergerValue:int = 1;
var nonIntegerValue:Number = 1.2;
var aSprite:Sprite = new Sprite();

var someFunction():void {
    // function code here
}

It’s true that variables and function return values could be strongly typed in ActionScript 2.0, and doing so was useful: the practice facilitated authoring tool assistance like code hinting, and provided more comprehensive error warnings at compile time—but compile time is where the benefits ended. Once a SWF file is produced, AVM1 loses any remembrance of an object’s type. AVM2 remembers.

Consistency

Ironically, one of ActionScript 3.0’s most elegant aspects is a potential stumbling block to longtime Flash developers, only because, as the adage goes, old habits die hard. Flash pioneers will remember when on() and onClipEvent() were not only the most popular ways to handle button and movie clip events, they were the only way. If you wanted to repeatedly trigger a custom function or simply a handful of instructions, you could associate your intentions with, say, the enterFrame event of a particular movie clip symbol. You could select the symbol, open the Actions panel—which was then temporarily linked to that symbol—and then type something like this:

onClipEvent(enterFrame) {
    // responsive code here
}

If you wanted to handle another event, you would use the same onClipEvent() function (the same formatting), in cahoots with that other event. Both event handlers were attached to the object in question:

onClipEvent(enterFrame) {
    // responsive code here
}
onClipEvent(release) {
    // mouse-related code here
}

When Flash MX hit the scene a few years later, the same basic concept took on a new alternative procedure, which was optional. In this other approach, event handling code could be attached to frames instead of directly to objects. This meant the desired recipient of your instructions—a movie clip, button, or the like—now needed an instance name, otherwise ActionScript would have no idea which object you were talking to. Instance names were usually provided by way of the Property inspector, but could also be determined by code. In the new format, dot notation provided the necessary association (here, the instance name is myClip):

myClip.onEnterFrame = function():Void {
    // responsive code here, inside
    // an anonymous function literal
}
myClip.onRelease = aNamedCustomFunction;
function aNamedCustomFunction():Void {
    // mouse-related code here, inside
    // a named function definition
}

The dot notation approach brought with it a number of benefits that often went unnoticed.

  • Finer grained control

    • 11 button events, versus the previous 8

    • 18 movie clip events, versus the previous 9

  • Easier maintenance, because code could be stored in a single frame, rather than scattered among potentially dozens of objects

  • More flexibility, as events could be assigned, deleted, and changed programmatically

As new versions of Flash Player continued to bring new functionality, two additional event handling mechanisms entered the developer’s lexicon: an addListener() method, used by such classes as Stage, MovieClipLoader, Key, and Mouse, and an addEventListener() method, used by ActionScript 2.0 components. Both of these new formats worked in a similar way, requiring an Object instance to act as liaison between the object in question and the methods defined by its class. The two could even share the same listener object:

var listener:Object = new Object();
listener.onKeyUp = keyUpHandler;
listener.click = clickHandler;

function keyUpHandler():Void {
    // keyboard-related code here
}
function clickHandler(evt:Object):Void {
    // button component code here
}

Key.addListener(listener);
myComponentButton.addEventListener("click", listener);

Because these additions happened over subsequent releases of the Flash authoring tool, longtime developers could add them piecemeal to their skill sets, but you can easily see how a newcomer might be mystified by so many choices.

In ActionScript 3.0, event handling has very nearly been consolidated into a single consistent approach, similar to the one used by ActionScript 2.0 components. In fact, the only exception happens with the NetStream class, and even then, only when you need to respond to video metadata or cue points. The exception still makes use of an Object instance, and shares many elements of the listener mechanisms in ActionScript 2.0 (exception cases in bold):

var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
videoPlayer.attachNetStream(ns);

var listener:Object = new Object();
listener.onMetaData = metaDataHandler;
listener.onCuePoint = cuePointHandler;

function metaDataHandler(evt:Object):void {
    // meta data code here
}
function cuePointHandler(evt:Object):void {
    // cue point code here
}

ns.client = listener;
ns.play("someVideoFile.flv");

Everything else uses the new EventDispatcher.addEventListener() method, which is inherited by all classes capable of dispatching events. Inheritance provides this event listening method in the same way it provides Sprite methods (and other functionality) to the MovieClip class, as touched on in the section entitled Efficiency of this chapter. Events of all of these objects—movie clips, buttons, components, text fields, the stage, sounds, programmatic tweens, instances of the new Timer class, and more—are handled the same way far and wide.

// Assuming instances of MovieClip, TextField, and Tween ...
myClip.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
myTextField.addEventListener(Event.SCROLL, scrollHandler);
myTween.addEventListener(TweenEvent.MOTION_FINISH,¬
     motionFinishHandler);

function enterFrameHandler(evt:Event):void {
    // responsive code here
}
function scrollHandler(evt:Event):void {
    // scroll-related code here
}
function motionFinishHandler(evt:TweenEvent):void {
    // tween-related code here
}

Note

For additional examples of ActionScript 3.0 event handling, see the section Creating DragParrot, a Sample Class File in Chapter 2; the section ActionScript Can No Longer Be Attached to Objects in Chapter 5; and the practical examples in Part III and Part IV of this book.

In addition to bringing together a consistent event handling model, ActionScript 3.0 unifies the approach employed to instantiate objects. In previous versions of ActionScript, you could easily create, for example, an array, string, or generic Object instance. The new statement neatly took care of it:

var a:Array = new Array();
var s:String = new String();
var o:Object = new Object();

Of course, some objects, such as these, had optional shortcut constructors (and still do):

var a:Array = [];
var s:String = "";
var o:Object = {};

but in either case, the construction of the desired object was a tidy process.

For other ActionScript 2.0 classes, notably MovieClip and TextField, it wasn’t so graceful. Instantiation of these objects required an existing MovieClip instance (often the main timeline, often referred to with this), to use the createEmptyMovieClip() and createTextField() methods:

var mc:MovieClip = this.createEmptyMovieClip("myClip", ¬
     this.getNextHighestDepth());
var tf:TextField = this.createTextField("myTextField", ¬
     this.getNextHighestDepth(), 0, 0, 100, 22);

As these objects were created, the MovieClip instance on which these methods were invoked became the immediate parent of the new movie clip or text field. In the code shown, this parent is the main timeline, via this, but any movie clip instance name would do, in which case the referenced movie clip would become the new object’s parent. Once it was established, you couldn’t change this parent/child relationship.

In ActionScript 3.0, even movie clips and text fields can be constructed with the new statement:

var mc:MovieClip = new MovieClip();
var tf:TextField = new TextField();

At this point, the mc and tf variables are bona fide instances of their respective classes. The movie clip can be drawn into with the Drawing API, positioned and animated over time. You can assign the text field plain text or HTML formatted text, and so on. When either object is ready for display, it can be added to the display list of any descendant of the DisplayObjectContainer class, which includes the main timeline, movie clips, sprites, and any class that supports the addChild() method. In this way, you can reparent visual objects in ActionScript 3.0 as often as you like.

Note

For more information on the display list concept, see the practical examples in Part IV of this book.

Standards and Portability Among Other Technologies

If your Flash development has led you into parallel work with HTML/XHTML, CSS, and JavaScript, you may already be familiar with the benefits of adherence to standards. The stakes in web development differ from those in Flash, because web developers have to make sure their content displays and behaves nearly the same—or, ideally, exactly the same—across a potentially sizeable number of browsers. This can be a sublimely challenging task, but the effort is reduced when browser manufacturers acknowledge and uphold the specifications on which these languages and technologies are based.

In contrast, Flash Player provides, for the most part, a single consistent runtime across any browser or operating system that supports the ActiveX control or plug-in. In the world of Flash development, the discipline involved in adhering to standards has already been taken care of. Adobe has leveraged this cohesive approach to let Flash developers step into the realms of Flex and AIR with relative ease. How? Because all of these tools rely on the same ActionScript 3.0 language, even though Flex and AIR support additional features.

Flex (http://www.adobe.com/products/flex/) is a highly productive, free open source platform for building and maintaining expressive web applications. The Flex framework, which includes dozens of visual layout components, user interface components, and data classes for connection to databases and web services, is written in ActionScript 3.0. This means that even though the Flex API contains new functionality, it operates with the same principles of performance, efficiency, and consistency demonstrated earlier in this chapter. Though its output overlaps with the sort of applications traditionally associated with Java or the .NET platform, Flex runs on ActionScript 3.0. If your interests lead you in the direction of Rich Internet Applications (RIAs), you’ll find that your barrier to entry is significantly reduced when you choose Flex as your path.

The Adobe Integrated Runtime (AIR) (http://www.adobe.com/products/air/) lets Flash, Flex, and Dreamweaver developers use their existing skills to build applications that deploy to the desktop. AIR integrates elements of the WebKit browser engine (used by Safari), Flash Player 10, and Acrobat to provide a rich environment for combining the benefits of traditional web technologies like HTML, CSS, and JavaScript with the multimedia aspects of Flash and the PDF file format. AIR also works with the SQLite database management system. Even among these varied avenues, ActionScript 3.0 provides a familiar apparatus for channeling the unique strengths of each into a unified user experience.

Get The ActionScript 3.0 Quick Reference Guide now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.