This post will show you the principle of an asynchronous queue, demonstrating it with the LinkedList structure in our package, used as a Queue by making it’s datatype nl.dpdk.collections.core.IQueue.
An Asynchrounous Queue is a queue that is processed with asynchrounous operations. Instead of processing a Queue in synchronous fashion, where you would remove all items from the queue in a loop, the items are removed only when the previous operation has finished (succesfully or not). The time when this is handled is not known in advance, and is event driven rather than procedurally driven.
Most browser cannot handle more than a couple of simultaneous http requests from flash, and just trying to load them all at once (in a loop) is error prone. A queue is a lifesaver in a case like this.
The reason for this demo is that we are building an application in papervision3d and want to load in some data to display a Plane. A Plane has lots of properties that define it: width, height, number of segments in 3d, x, y and z coordinates and some other 3d engine related stuff. It also needs a ‘material’ as a texture, which we are loading at runtime as jpg files. In our case we would like to be able to preserve the other properties that we are first loading in from an xml file, so we can add the material with the right plane properties to the 3d engine after the jpg file defining the texture has loaded.
The flow of the asynchronous queue in the context of loading stuff is as follows:
- create a queue of objects. Each object has some properties, including the url of an asset to load
- peek at the first object in the queue (peek does not remove an item, it just allows you to look at it)
- define succes handlers and error handlers for loading the asset
- start loading the asset from the object you peeked at
- the handler that is fired calls the dequeue operation on the list
- the object reference from the dequeue can be used to retrieve the data of the last loaded item
- the loaded asset itself is also available, so it can be used for display purposes, also using the other data from the dequeued object
- start peeking again. if the queue returns a null reference, stop loading cause the queue is empty and do your ending thing. If it is not empty, continue loading
here is some code to demonstrate it.
package nl.dpdk.demo.AsynchronousQueueDemo { import nl.dpdk.collections.core.IQueue; import nl.dpdk.collections.lists.LinkedList; import flash.display.Loader; import flash.display.MovieClip; import flash.events.Event; import flash.events.HTTPStatusEvent; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.net.URLLoader; import flash.net.URLRequest; public class AsynchronousQueueDemo extends MovieClip { //queue to hold some data, of datatype IQueue private var list : IQueue = new LinkedList(); public function AsynchronousQueueDemo() { loadData(); } /** * loads some xml configuration data */ private function loadData() : void { XML.ignoreWhitespace = true; var loader : URLLoader = new URLLoader(); loader.addEventListener(Event.COMPLETE, onXMLLoaded); loader.load(new URLRequest("./xml/data.xml")); } /** * xml data loaded, now process it and start doing the asynchronous loading operation via a queue */ private function onXMLLoaded(event : Event) : void { var loader : URLLoader = event.target as URLLoader; var xml : XML = new XML(loader.data); processXML(xml); //all things are ready to be loaded loadNext(); } private function processXML(xml : XML) : void { /** * xml structure is: * * * * * */ //thing stores data we want to use later var thing : Thing; for each(var xmlElement: XML in xml.*) { thing = new Thing(xmlElement.@file, xmlElement.@id); //put things in the queue list.enqueue(thing); } } /** * method gets called each time a new thing needs to be loaded. * It also handles the last item after it has been loaded */ private function loadNext() : void { //look at the next thing in the list, but DO NOT remove, so we can retrieve the data in the thing instance later var thing : Thing = list.peek() as Thing; //if there is something to be done... if(thing != null) { //load the thing loadThing(thing); }else { //nothing to load, loading finished, end the asynchronous queue here... doYourThing(); } } /** * loads a specific thing. * also adds all loading related event handlers */ private function loadThing(thing : Thing) : void { try { var loader: Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onThingError); loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onThingError); loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, onThingError); loader.load(new URLRequest(thing.file)); }catch(e : Error) { //allow processing to continue in case something happened onThingError(null); } } /** * loading errors. * The loading should continue after this, so the flow will not stop */ private function onThingError(event : IOErrorEvent) : void { //remove bad thing list.dequeue(); //load next thing loadNext(); } /** * loading succes. */ private function onLoadComplete(event : Event) : void { //remove a thing from the list as it has been loaded var thing : Thing = list.dequeue() as Thing; //do stuff with the thing! trace("thing loaded: " + thing.id); //load next thing loadNext(); } private function doYourThing() : void { //do your thing here.... everything is loaded } } }
0 Responses to “Asynchronous queue demo with a LinkedList”
Leave a Reply