Chances are you’ve been bitten by the ErrorEvent class at some point while programming AS3. It’s the asynchronous equivalent to throw an Error and it happens when, for example, a Loader‘s load fails. If you write any code that performs an asynchronous task, perhaps more file loading, you too may want a way to inform users of your class that the task has failed. Just like with Event, it’s nice to be able to add data on to the standard ErrorEvent class. How does this work? Let’s dig in and find out.

First, an example of how ErrorEvents are used in the Flash API. Here’s a bit of code to load an image:

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest("image.jpg"));
 
function onLoadComplete(ev:Event): void
{
    // do something with the image
}

Now suppose that image.jpg can’t be loaded, such as when it’s not found on the hard drive or a server returns the dreaded “404” error code. There are a variety of ways the load can fail, but here’s one of the possible messages you’ll see in a debug Flash Player popup window:

Error #2044: Unhandled IOErrorEvent:. text=Error #2036: Load Never Completed.

This is because handling ErrorEvent events is mandatory. This includes subclasses like Flash’s IOErrorEvent above. To suppress this crash all you have to do is listen for the event like so:

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
loader.load(new URLRequest("image.jpg"));
 
function onLoadComplete(ev:Event): void
{
    // do something with the image
}
 
function onLoadError(ev:Event): void
{
    // do something with the error (or not)
}

So how about if we want to create our own ErrorEvent and require our users to listen for it, lest they get a crash? Well, it turns out that all you need to do is subclass ErrorEvent and dispatch one. Here’s an example of a class that loads up two images:

public class TwoImagesLoadErrorEvent extends ErrorEvent
{
    public static const LOAD_ERROR:String = "loadError";
 
    public var image1:DisplayObject;
    public var image2:DisplayObject;
 
    public function TwoImagesLoadErrorEvent(image1:DisplayObject, image2:DisplayObject)
    {
        super(LOAD_ERROR);
        this.image1 = image1;
        this.image2 = image2;
    }
}
public class TwoImageLoader extends EventDispatcher
{
    private var loader1:Loader;
    private var loader2:Loader;
 
    private var image1:DisplayObject;
    private var image2:DisplayObject;
 
    public function TwoImageLoader(url1:String, url2:String)
    {
        loader1 = load(url1, onImage1Loaded);
        loader2 = load(url2, onImage2Loaded);
    }
 
    private function load(url:String, onSuccess:Function): Loader
    {
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onSuccess);
        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
        loader.load(new URLRequest(url));
        return loader;
    }
 
    private function onImage1Loaded(ev:Event): void
    {
        image1 = loader1.content;
        if (image1 && image2)
        {
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
 
    private function onImage2Loaded(ev:Event): void
    {
        image2 = loader2.content;
        if (image1 && image2)
        {
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
 
    private function onLoadError(ev:Event): void
    {
        dispatchEvent(new TwoImagesLoadErrorEvent(image1, image2));
    }

To use this class, it’s just as with Flash API classes like Loader:

var twoImagesLoader:TwoImagesLoader = new TwoImagesLoader("img1.jpg", "img2.jpg");
twoImagesLoader.addEventListener(Event.COMPLETE, onSuccess);
twoImagesLoader.addEventListener(TwoImagesLoadErrorEvent.LOAD_ERROR, onError);
 
function onSuccess(ev:Event): void
{
    // do something with the images, like lay them out vertically...
 
    addChild(twoImagesLoader.image1);
 
    twoImagesLoader.image2.y = twoImagesLoader.image1.height;
    addChild(twoImagesLoader.image2);
}
 
function onError(ev:TwoImagesLoaderErrorEvent): void
{
    trace("couldn't load images. image1=" + ev.image1 + ", image2=" + ev.image2);
}

This custom TwoImagesLoaderErrorEvent contains the two images that were loaded (or not) and lets us salvage the one that was loaded. Since the loads can happen in any order, we don’t know which will load and which will fail. Above we just log out a more informative error message, but more could be done. In the success case the images are laid out vertically. In the error case, a “missing image” placeholder could replace the one that didn’t load.

In summary, a custom ErrorEvent class can be a useful tool when writing asynchronous AS3 code. You gain conformity with the Flash API which, presumably, all Flash programmers already know. You also gain the ability to make handling your error event mandatory, lest their be a crash. This is much more useful than simply firing an Event derivative that has “error” in its name but can be ignored, perhaps to the peril of the application.

Spot a bug? Have a suggestion or question? Post a comment!