DIGG IT!
Published
Wednesday, August 19, 2009
at
3:34 PM
.
Today I posted build 32 for public download of Project FDOT( f.* ). FDOT is a collection of ActionScript 3 classes that make hard things easier.
DOWNLOAD FDOT_BUILD_32The first release includes 3 classes:
f.net.Load - Load text to binary with one method call and one callback.
f.net.Message - Simple callback messaging for classes.
f.data.ObjectStore - Simple object database for storing anything.
(Includes an awesome JSON lib by Darron Schall via as3corelib )
The first thing that you will notice in FDOT is a sharp departure from OOP and addEventListener in preference for simpler method calls and the use of callbacks. I have long felt that addEventListener is overkill and with the addition of method closures, callbacks are a very underrated technique. Loading external data in Flash Player used to be drop dead easy, like no think easy. Today it isn't, it typically requires you to subscribe to 5 events create 5 methods all typed to catch different events and even then knowing what to do when things happen leaves many frustated. Why was this so easy before? Why do we need to do all this work just to load data or swf files?
The thing is that having great low level networking classes is great but we need to build simpler code upon these. That is the intent behind f.net.Load. Simplify the loading of all types of data into Flash Player. Make it clean, orthogonal, and easy to use. Here are some samples:
//note that all Load methods have the exact interface!
Load.text( url:String , callback:Function , params:Object=null );//text
//load text via post using this.load method as callback
Load.text( 'test.txt' , load , { method:'post', data:{ a:1 } } );//json
Load.json( 'test.json' , load , { method:'post', data:{ a:1 } } );//xml
Load.xml( 'test.xml' , load , { method:'post', data:{ a:1 } } );see a trend yet?//querystring
Load.querystring( 'test.qs' , load , { method:'post', data:{ a:1 } } );//stream
Load.stream( 'test.png' , load , { method:'post', data:{ a:1 } } );//image
Load.image( 'test.png' , load , { method:'post', data:{ a:1 } } );//swf
Load.swf( 'test.swf' , load , { method:'post', data:{ a:1 } } );//binary
Load.binary( 'test.png' , load , { method:'post', data:{ a:1 } } );The best part is that you need only one method to handle all callbacks. Here is how it works. Simply define a method with a single Object as its parameter, your done. Based on the 'type' property within the object passed in the callback you get different data. Some callbacks are for Load.PROGRESS, Load.OPEN, Load.HTTPSTATUS and you can use these constants to filter like so:
public function load( event:Object ):void
{
if( event.type == Load.COMPLETE ){
trace( ' < loadMovie COMPLETE: ' + event.data );
}else if( event.type == Load.PROGRESS ){
trace( ' < loadMovie PROGRESS: ' + event.percent );
}
}When Load.COMPLETE is passed, you get event.data, and when Load.PROGRESS, you get event.percent, event.bytesLoaded, etc within the passed object. I have been thinking about making a single callback Event type to make this easier still but that is for a future version.
In the build there are samples of every feature of the FDOT library. I am working to add in ASDOC comments and get the initial documentation generated too along with some late breaking additions of Load.amf, Load.csv, and Load.yaml, pending massive disruptions. Also planning to expand the features within the parameters argument to support PRAGMA headers, Caching support via ObjectStore, and a server side proxy to allow for full REST support ( I might need some CF/PHP/JAVA help there).
I would ask that if you find any bugs, email me at ted@adobe.com. Plans are underfoot to move this under GITHUB later today but some networking is holding me back, ugggh.
The goal here is to make hard stuff simpler so you can spend your time making awesome complex stuff. Loading has been a huge barrier for Flash Player since ActionScript 3 arrived and I would hope this helps a bit. Long story short simplicity and ease of use are driving all API decisions on FDOT, and if you see a simpler path, I am all ears.
DOWNLOAD FDOT_BUILD_32It has been a blast working on FDOT and it is great to set it free as open source under a BSD License. Use it as you wish and send me feedback on what to do next.
Cheers,
Ted :)
Awesome work. Can't wait to see this go onto Github and see what the community can offer back.
I'm all about that. I came into my own during the AS2 heyday and while I really dig what AS3 brought to the table it did definitely complicate things that used to be simple.
I think that we think along the same lines. I just released a library that I use to make my code easier to write; though it's more generic and FDOT addresses specific tasks that need to be simplified.
My only suggestion to make things easier for me to use this as a utility (specifically the load) is to eliminate the "type" property checking and instead pass a strongly typed object from which I can glean the state of the load. (For instance a .complete bool, a .percComplete value, etc)
Maybe it is more clean to not use Static methods, for performance, inheritance and testing.
Great...
Jonathan,
By using all statics the option to add instance behavior remains an option. Would be trivial to add:
var ldr:Load = new Load( type, url , callback, params );
The load object would have properties you can check as Jason mentioned shoot you can even dispatch events as things occur.
As a first pass an all static implementation left room for making Load into instances yet using the Static logic within.
Ted :)
really useful stuff... hopefully these can sneak into the official flash.data/net namespace one day ;)
the use of callbacks on the Load methods is really interesting... makes ya think twice before using event listeners... esp for loading and sockets
is there much overhead for casting the callback function to an Object compared to an Event? (in your example)
Maybe a compare and contrast post on the old way vs. the new way would be good?
There is a small hit for using Object for the event obj. Planning to make a LoadEvent class with typed members. Also looking at adding instance behavior via ld:Load = new Load( Load.XML, ...)
Callbacks are just a function call. The cool part is that every function in AS3 is tied to something (Class or instance) via closures. So you can pass a Function and it will execute in the context of the object that owns it. 99% of the time when loading data only 1 thing needs to listen and addEventListener is tuned for N listener functionality.
Ted :)
Cool.
What do you think of separate "on success" vs. "status/failure" callbacks? In PushButton Engine's loading code, we have "on succeed" and "on fail" callbacks for loading - most of the time people do nothing in the on fail case, and on succeed just passes them the loaded item.
Ben,
I do like the single callback but it definitely needs a typed Event. success/fail is a great way to structure events on loading, I would add progress in there. HTTPStatus is an odd duck. It occurs if status is returned from server, this data should be available within success event. Also events for securityerror and IOError should be data in FAIL. OPEN/CLOSE/INIT are interesting, these are more when socket connects and INIT is when loaded SWF starts. This might be all that is needed where INIT is limited to SWF loading.
LoadEvent.SUCCESS
LoadEvent.FAIL
LoadEvent.PROGRESS
LoadEvent.INIT
Thoughts?
Ted :)
Well, I think the benefit is you get the common case (I only care about when it worked) with one callback, and the other optional one gives you progress, failure, etc. So you can hack something up quick, then go back and add proper error handling/sanity checking/status reporting where you care.
In PBE's case, many resource loads happen from within the SWF so can never fail. So a lot of the time you really don't care.
That detail aside, you're onto good things here. :) Having some of the retry/queueing behavior that BulkLoader does would be handy.
Intriguing work. Any thoughts about how your project compares with bulk loader (http://code.google.com/p/bulk-loader/)?
yes, you are right.
addEventListeners(), when used with named functions have a big plus: you can call removeEventListener(). This is important in some memory intensive applications.
If you use anonymous function handlers with addEventListener(), GC won't be able to remove them, if need be.
Will you class allow removing the closure from memory?
Yakov,
Once a loading has completed or failed, the class cleans up all references. The method/function is stored as a property within the request object. This reference is deleted just before the whole request object is deleted as a reference. In tests, the memory for all functions is released given each and every reference is carefully cleaned up.
Ted :)
This is flipping awesome. Perfect for designers with a little dev experience, like myself. I'm slowly formalizing similar shortcuts for AIR on livebrush.org.