Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Complete overhaul of the project; as3-async now deals with providing …
…a clean and compact `Promise` implementation. Source, Test coverage and Examples for the project. Need to continue work on the documentation and update the README.
- Loading branch information
1 parent
fb85f13
commit 87688be
Showing
15 changed files
with
1,062 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,4 @@ | ||
AS3 Async | ||
========= | ||
|
||
Utilities for working with asynchronous code in ActionScript 3. This library is open source and participation from | ||
others is encouraged! :) | ||
|
||
when | ||
---- | ||
Provides a convenient way of handling Events using closures. All mappings are automatically cleaned up by default, | ||
but they can be made to persist by setting the `oneShot` argument to `false`. | ||
|
||
```actionscript | ||
package app.service { | ||
public class DataLoader extends EventDispatcher { | ||
private var _url : String; | ||
private var _parser : IDataParser; | ||
public function DataLoader(url : String, parser : IDataParser) { | ||
_url = url; | ||
_parser = parser; | ||
} | ||
public function load() : void { | ||
const urlLoader : URLLoader = new URLLoader(); | ||
// Create a mapping that will listen for Event.COMPLETE being dispatched by urlLoader. | ||
when(urlLoader, Event.COMPLETE, function () : void { | ||
// This code is invoked when the event is fired, because we are inside a closure | ||
// it can access properties from the parent function and parent Class. | ||
const data : MyData = _parser.parse(urlLoader.data); | ||
// In this example we dispatch a custom Event to let the rest of the system know | ||
// something has happened. | ||
dispatchEvent(new DataLoadedEvent(DataLoadedEvent.DATA_LOADED, data)); | ||
}); | ||
urlLoader.load(new URLRequest(_url)); | ||
} | ||
} | ||
} | ||
``` | ||
A clean and compact implementation of the [Promise pattern](http://en.wikipedia.org/wiki/Futures_and_promises). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package | ||
{ | ||
import org.osflash.async.DeferredEventDispatcherExample; | ||
|
||
import flash.display.Sprite; | ||
/** | ||
* @author jonny | ||
*/ | ||
public class Main extends Sprite { | ||
new DeferredEventDispatcherExample(); | ||
//new BenchmarkWhen(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.osflash.async { | ||
import org.osflash.async.Promise; | ||
import org.osflash.async.mocks.SimpleDeferred; | ||
import org.osflash.async.when; | ||
|
||
import flash.utils.getTimer; | ||
import flash.utils.setTimeout; | ||
/** | ||
* @author jonny | ||
*/ | ||
public class BenchmarkWhen | ||
{ | ||
private var REPS : int = 250000; | ||
private var DEF_DELAY : int = 10000; | ||
|
||
private var _startTime : uint; | ||
private var _promises : Array; | ||
|
||
public function BenchmarkWhen() | ||
{ | ||
|
||
setTimeout(run, 2000); | ||
} | ||
|
||
private function run() : void { | ||
setup(); | ||
|
||
_startTime = getTimer(); | ||
trace("Deferreds Created: " + _startTime); | ||
|
||
const promise : Promise = when.apply(null, _promises); | ||
promise.completes(function() : void { | ||
const totalTime : Number = getTimer() - _startTime; | ||
trace("Benchmark complete in: " + totalTime + ", when execution time: " + (totalTime - DEF_DELAY).toString()); | ||
}); | ||
} | ||
|
||
private function setup() : void | ||
{ | ||
_promises = []; | ||
for (var i : uint = 0; i < REPS; i++) { | ||
_promises.push(new SimpleDeferred(true, DEF_DELAY)); | ||
} | ||
} | ||
|
||
|
||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
examples/org/osflash/async/DeferredEventDispatcherExample.as
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package org.osflash.async | ||
{ | ||
import org.osflash.async.impl.TweetVO; | ||
import org.osflash.async.impl.XMLTweetParser; | ||
|
||
import flash.events.Event; | ||
import flash.events.IOErrorEvent; | ||
import flash.net.URLLoader; | ||
import flash.net.URLRequest; | ||
|
||
/** | ||
* @author Jonny | ||
*/ | ||
public class DeferredEventDispatcherExample | ||
{ | ||
public function DeferredEventDispatcherExample() | ||
{ | ||
when(fetchTweetsFor("catburton"), fetchTweetsFor("jonnyreeves")) | ||
.completes(function() : void { | ||
trace("Got Tweets yo!"); | ||
}) | ||
.completes(onTweetsFetched) | ||
.fails(onFailed); | ||
} | ||
|
||
private function fetchTweetsFor(username : String) : Promise | ||
{ | ||
const urlLoader : URLLoader = new URLLoader(); | ||
const deferred : DeferredEventDispatcher = new DeferredEventDispatcher(urlLoader) | ||
.resolveOn(Event.COMPLETE, function(event : Event) : Vector.<TweetVO> { | ||
return new XMLTweetParser().parse(urlLoader.data); | ||
}) | ||
.rejectOn(IOErrorEvent.IO_ERROR); | ||
|
||
urlLoader.load(new URLRequest("https://api.twitter.com/1/statuses/user_timeline.xml?screen_name=" + username + "&count=3")); | ||
return deferred.promise(); | ||
} | ||
|
||
private function onFailed(error : Error) : void | ||
{ | ||
trace("Failed to fetch tweets: " + error); | ||
} | ||
|
||
private function onTweetsFetched(outcomes : Array) : void | ||
{ | ||
trace("Fetched " + outcomes.length + " sets of Tweets"); | ||
|
||
for each (var tweets : Vector.<TweetVO> in outcomes) { | ||
trace(tweets.join("\n")); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.osflash.async.impl | ||
{ | ||
/** | ||
* @author Jonny | ||
*/ | ||
public class TweetVO | ||
{ | ||
public var id : String; | ||
public var message : String; | ||
|
||
public function toString() : String | ||
{ | ||
return message; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package org.osflash.async.impl | ||
{ | ||
/** | ||
* @author Jonny | ||
*/ | ||
public class XMLTweetParser | ||
{ | ||
public function parse(data : *) : Vector.<TweetVO> | ||
{ | ||
const xml : XML = new XML(data); | ||
const result : Vector.<TweetVO> = new Vector.<TweetVO>(); | ||
|
||
for each (var status : XML in xml..status) { | ||
const tweet : TweetVO = new TweetVO(); | ||
tweet.id = status.id; | ||
tweet.message = status["text"]; | ||
|
||
result.push(tweet); | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package org.osflash.async | ||
{ | ||
/** | ||
* A Deferred object provides the means to fulfil a Promise by the means of calling 'resolve', 'reject' and | ||
* 'progress'. Typlically a Deferred object is instantiated and retained by a client so that when the operation | ||
* completes, rejects, or progresses, the appropriate methods can be invoked. The client can invoke 'abort' if | ||
* the Deferred operation needs to be terminated (in which case none of the callback will be invoked.) | ||
* | ||
* A Deferred object uses a finite state machine to ensure that it can only transition from PENDING to one of | ||
* either RESOLVED or REJECTED to ensure that the Promise gets resolved in a predicable fashion. | ||
* | ||
* @author Jonny Reeves. | ||
*/ | ||
public class Deferred implements Promise | ||
{ | ||
private static const PENDING : uint = 0; | ||
private static const RESOLVED : uint = 1; | ||
private static const REJECTED : uint = 2; | ||
private static const ABORTED : uint = 3; | ||
|
||
private const _completeListeners : Vector.<Function> = new Vector.<Function>(); | ||
private const _failListeners : Vector.<Function> = new Vector.<Function>(); | ||
private const _progressListeners : Vector.<Function> = new Vector.<Function>(); | ||
|
||
private var _finalCallback : Function; | ||
private var _state : uint = PENDING; | ||
private var _outcome : *; | ||
|
||
/** | ||
* Notifies all 'completes' handlers that the deferred operation was succesful. An optional outcome object | ||
* can be supplied which will provided to all the complete handlers. | ||
* | ||
* @parm outcome The optional result of the Deferred operation. | ||
*/ | ||
public function resolve(outcome : * = null) : void | ||
{ | ||
if (_state != PENDING) { | ||
return; | ||
} | ||
|
||
_outcome = outcome; | ||
_state = RESOLVED; | ||
|
||
const len : uint = _completeListeners.length; | ||
for (var i : uint = 0; i < len; i++) { | ||
_completeListeners[i](_outcome); | ||
} | ||
|
||
clearListeners(); | ||
invokeFinalCallback(); | ||
} | ||
|
||
/** | ||
* Notifies all 'fails' handlers that this deferred operation has been unsuccesful. The supplied Error object | ||
* will be supplied to all of the handlers. | ||
* | ||
* @param error Error object which explains how or why the operation was unsuccesful. | ||
*/ | ||
public function reject(error : Error) : void | ||
{ | ||
if (_state != PENDING) { | ||
return; | ||
} | ||
|
||
// By contact, we will always supply an Error object to the fail handlers. | ||
_outcome = error || new Error("Promise Rejected"); | ||
_state = REJECTED; | ||
|
||
const len : uint = _failListeners.length; | ||
for (var i : uint = 0; i < len; i++) { | ||
_failListeners[i](_outcome); | ||
} | ||
|
||
clearListeners(); | ||
invokeFinalCallback(); | ||
} | ||
|
||
/** | ||
* Notifies all of the 'progresses' handlers of the current progress of the deferred operation. The supplied | ||
* value should be a Number between 0 and 1 (although there is no fixed validation). Once the deferred | ||
* operation has resolved further progress updates will be ignored. | ||
* | ||
* @param ratioComplete A number between 0 and 1 which represents the progress of the deferred oepration. | ||
*/ | ||
public function progress(ratioComplete : Number) : void | ||
{ | ||
const len : uint = _progressListeners.length; | ||
for (var i : uint = 0; i < len; i++) { | ||
_progressListeners[i](ratioComplete); | ||
} | ||
} | ||
|
||
/** | ||
* Aborts the deferred operation; none of the handlers bound to the Promise will be invoked; typically this | ||
* is used when the Deferred's host needs to cancel the operation. | ||
*/ | ||
public function abort() : void | ||
{ | ||
_state = ABORTED; | ||
_outcome = null; | ||
_finalCallback = null; | ||
|
||
clearListeners(); | ||
} | ||
|
||
public function completes(callback : Function) : Promise | ||
{ | ||
if (_state == PENDING) { | ||
_completeListeners.push(callback); | ||
} | ||
else if (_state == RESOLVED) { | ||
callback(_outcome); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
public function fails(callback : Function) : Promise | ||
{ | ||
if (_state == PENDING) { | ||
_failListeners.push(callback); | ||
} | ||
else if (_state == REJECTED) { | ||
callback(_outcome); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
public function progresses(callback : Function) : Promise | ||
{ | ||
if (_state == PENDING) { | ||
_progressListeners.push(callback); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
public function thenFinally(callback : Function) : void | ||
{ | ||
_finalCallback = callback; | ||
} | ||
|
||
private function clearListeners() : void | ||
{ | ||
_completeListeners.length = 0; | ||
_failListeners.length = 0; | ||
_progressListeners.length = 0; | ||
} | ||
|
||
private function invokeFinalCallback() : void | ||
{ | ||
if (_finalCallback !== null) { | ||
_finalCallback(); | ||
_finalCallback = null; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.