AS3 doLater/todo Function Queue

While working on my windowing system I ran into a problem. Every time I tried to set the width of my window class instance I’d get an error from my bitmap resource handler telling me the resources hadn’t been loaded. This makes it impossible to set widths for a window before it’s loaded, and since the entire system is supposed to be deployable online, loading time is not anything I can count on. I wrote this small class to take care of executing functions at a given time (like after loading is finished). The class is called Queue and here is some usage:

import com.efnx.utils.Queue;

function blah(val1:int, val2:int):void
{
    trace(val1+val2);
}

function blah2(val1:int, val2:int):void
{
    trace(val1+val2);
}

var queue:Queue = new Queue();
    queue.push(blah, 1, 5);
    queue.push(blah, 2, 5);
    queue.push(blah, 4, 5);
    queue.push(blah2, 3, 5);
   
   
trace(queue);

queue.start();

That code does this -> First we define two different functions, blah and blah2. Then we push the functions to be executed into the queue. Here’s the interesting part. Since the Dictionary Object inside the class used to list functions is not weakly referenced Duplicate entries cannot be made by the same function regardless of it’s parameters. In the the example above I push blah into the queue three times, but the only one that fires and traces is the third because the queue’s key is the function itself [or the "closure object (ie. the "behind the scenes" object that facilitates method closure by maintaining a reference back to the method and its scope)" as described by Grant Skinner], so the function replaces itself in the queue. This is nice for doing things like setting widths and resizing, although not so great for things like sending different strings to some handler. As of now calling start() applies the functions asynchronously and nullifies anything left in the queue. You’ll see the output traces this:

object [Queue]
->  function Function() {}  3,5
->  function Function() {}  4,5
8
9

First it traces the Queue Object which contains references to the two functions and their parameters (not in the order we gave them) then the output. Bam! Done. Oops! Not quite… …At any point you can flush the queue without executing the functions by calling abort(). There, done.

This class can be easily extended or modified to include directives to execute functions in a given order or multiple entries of one function, so get crackin!

Source
Queue Class Source Code

Tags: , , , , ,

4 Responses to “AS3 doLater/todo Function Queue”

  1. Let me add that while using this class it is very easy to see how methods stored in a weakly referenced Dictionary object are immediately collected.

  2. Hi Schell,

    I was looking at the code you posted to my site. I wanted to make a few notes that may help out.

    First, the order of the trace has to do with the for…in loop that you use in the toString() method. This loop doesn’t necessarily output in the order you added the functions.

    Second, this isn’t happening as a result of weak references. As you mentioned on your blog post, you cannot use the same function twice as a key without overwriting the previous value. In a Dictionary, the key object acts the same as an index for an array. If you had

    var a:Array = new Array();
    a[0] = “foo”;
    a[1] = “bar”;
    a[1] = “woot”;
    trace(a); // foo,woot

    so it stands to reason that you shouldn’t be able to do this with functions as keys either.

    Since this class essentially runs a list of functions one after the other, you may want to try using dynamic Functions instead. Something like this:

    var func:Function = new Function ():void {
    blah (1, 5);
    blah (2, 5);
    blah (4, 5);
    blah2(3, 5);
    }
    func();

    I hope that was helpful.

  3. Yes, I see that my toString() wouldn’t trace the list of functions in the order that they were listed, but without adding another variable to keep track of the order added, how would you trace or execute them first come first serve? It seems like the order it traces in is the same order it executes in.

    Another note: the interesting thing about this class isn’t how the methods are replaced, but because (contrary to posts I had read regarding the matter -> http://gskinner.com/blog/archives/2006/07/as3_dictionary.html) I couldn’t create duplicate function entries with the same method (in a weakly referenced Dictionary).

    My main point was that changing the Dictionary’s reference (weak or strong) changes the output of the code I posted on your blog. For example, changing the code I had posted above to instantiate my Queue class with a ’strong’ referenced Dictionary, the output is as follows:

    object [Queue]
    -> function Function() {} 3,5
    -> function Function() {} 4,5
    8
    9
    object [Queue]
    done

    As you can see calling toString() on the class traces the contents (in whatever order it decides) and then executes the functions in that same order. Instantiating the class with a weakly referenced Dictionary results in the following:

    object [Queue]
    -> function Function() {} 4,5
    -> function Function() {} 3,5
    object [Queue]
    done

    Here you can see that immediately after pushing the functions into the Queue, the functions can be listed, but after the TimerEvent.TIMER (which is set to 1 millisecond) has triggered, the functions that were once listed are no longer there!

    I may be missing the point, but I never explicitly removed the functions from the queue, yet they disappeared. When the class is instantiated with a strong referenced Dictionary the functions last and are executed. I don’t know what else to attribute this behavior to besides the GC. Maybe you can help me understand this more clearly.

  4. Thanks for the class, came in handy.

Leave a Reply


Follow me on GitHub
Follow me on Google+
Follow me on Twitter
Thrilling.
EFNX is proudly powered by WordPress
Entries (RSS) and Comments (RSS).