LogoLogo
  • Home
  • Projects
  • About
  • Contact

Promises Promises

Devon O. · March 18, 2013 · Actionscript · 2 comments
15

The other day at work we needed to re-think the way we were handling asynchronous tasks. In essence, we needed a way to (cleanly!) ensure one task was complete before moving on to the next. Very casually, my boss suggested we implement a ‘Promise’ pattern. Feeling a bit like a fool for having no idea what he meant, I did a bit of Googling and discovered in Actionscript land it’s a very rare concept, so I thought I’d take a bit of time and write about it (mainly to better understand it myself).

Before diving into what promises are, though, I’ll take a look at the problem they solve. What it boils down to is handling asynchronous tasks (such as asset loading, for example) in a clean, intelligent fashion. In the world of Flash and Actionscript, you’ll typically find two strategies for this type of behavior: a ‘bulk loading’ approach, and an ‘event chaining’ approach.

In bulk loading, you’ll usually see a BulkLoader object which gets passed tasks (asset loading tasks typically). It’s usually left up to the BulkLoader to sort out the types of tasks (is it loading an xml file or a png file) and to keep track of when it’s complete. Normally you would see a numLoaded variable increased on every successful load which is then compared to a numToLoad variable. If they are equal, a ‘complete’ event is dispatched. If anything fails along the way, an ‘error’ event is dispatched. This isn’t a bad way to go (I’ve done it more times than I can count), but it has one major drawback: what if you need tasks performed in a very specific sequence and tasks in the middle of the sequence depend on the output of previous tasks (e.g. what if you load an xml or json file and values within it are used to load additional objects)? Now it would be possible to build an intelligent BulkLoader object that performs tasks in the order in which they’re added passing output to input, but that could become an unmanageable mess real quick like.

More often than not, this is where the event chaining approach comes in. Let’s say, for the sake of argument, you’re working on a game and in order for that game to start successfully, it must perform these tasks in this order:

  1. Load graphics (e.g. sprite sheet(s))
  2. Load sounds
  3. Load player info
  4. Load high scores
  5. Initialize the game using all of the above

Only then can the game start and if any of those tasks fail, an error message should be shown and the sequence should start again. Typically, you’ll see a task list like this chained up using ‘onSuccess’ and ‘onError’ callback methods. Something sorta like this:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
this.assets.getGraphics(onGraphicsSuccess, onError);
 
private function onError():void
{
    // The sequence has failed. Try again
}
 
private function onGraphicsSuccess(gdo:GameDataObject):void
{
    this.assets.getSounds(onSoundSuccess, onError, gdo);
}
 
private function onSoundSuccess(gdo:GameDataObject):void
{
    this.player.getPlayerInfo(onPlayerInfoSuccess, onError, gdo);
}
 
private function onPlayerInfoSuccess(gdo:GameDataObject):void
{
    this.game.getHighScores(onHighScoreSuccess, onError, gdo);
}
 
private function onHighScoreSuccess(gdo:GameDataObject):void
{
    this.game.init(gdo);
    this.game.start();
}

Again, there is nothing inherently horrible about this approach. Like the bulk loading method, I’ve done it a countless number of times and it always works. As you can see though, as your code base grows, this approach can quickly become unmanageable and messy – especially if you need to add or remove a task from the middle of the sequence.

This is where the ‘Promise’ pattern (or construct or whatever its correct designation may be) comes in. The ‘Promise’ approach takes the above chaining method and codifies it into a neat and readable api. It does so by exposing a ‘then()’ method which accepts your onSuccess and onError callbacks and returns a new Promise object. Using a Promise, the example above can be re-written to look like this:

C#
1
2
3
4
5
this.assets.getAssets()
    .then( this.player.getPlayerInfo )
    .then( this.game.getHighScores )
    .then( this.game.init )
    .then( onLoadSequenceComplete, onLoadSequenceError );

Just take a moment to look at how clean and elegant that is. It reads like a simple to-do list. Even a non-coder can see exactly how to add a new task to the middle of that sequence. Now the inner workings of a Promise are slightly more complex, but not much. Essentially when a Promise completes, it should be ‘resolved’ which will automatically call its onSuccess callback. Likewise, should a promise fail, it should be ‘rejected’ which will call its onError callback, which, in turn, should throw an error (a try..catch block within the promise construct will allow you to gracefully handle the thrown error).

And that is really all there is to it.

I know I’ve pretty much just glossed over the usage and explanation here, and there is, obviously, much more to promises, but there are better places for more details, so here’s a quick list:

the best AS3 Promise implementation I’ve come across
a complete example I put together using the above implementation (on Wonderfl)
a good ol’ Wikipedia article
a look at promises in javascript
a very good in depth article

 

  Facebook   Pinterest   Twitter   Google+
asynchronous
  • Promises Promises
    March 18, 2013 · 2 comments
    42974
    15
    Read more
  • Quick QuickBox2D Tip II – Collision Detection
    May 06, 2010 · 5 comments
    3307
    7
    Read more
  • The Old Snow Trick – In the Third Dimension
    February 13, 2008 · 0 comments
    1750
    2
    Read more
2 Comments:
  1. Promises are fun. BTW, that Deferred implementation I wrote was just a quick port of the CoffeeScript version here:

    https://github.com/CodeCatalyst/promise.coffee

    The original author has also released an AS3 version:

    https://github.com/CodeCatalyst/promise-as3

    shaun · March 18, 2013
  2. Hey Shaun,

    Thank you for the comment. And, moreso, thank you for the sharing your AS3 Deferred implementation. I did run across promise-as3 (from the author of promise.coffee) but wasn’t keen on the flex dependencies. I’m sure it wouldn’t have been difficult to remove them, but then I ran across yours and didn’t have to bother. Only thing I still don’t like is that sprite instance hanging out in there for the enterframe tick. In any case we need to write a custom implementation to fit with what we have at work anyway, but your work will be a great starting place, so thanks again.

    d.

    Devon O. · March 19, 2013

Leave a Comment! Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • MainDepth on Unity Ripple or Shock Wave Effect
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2021 Devon O. Wolfgang