28 March 2010

as3signals: new approach for AS3 Events

There are times you may find that the built-in events of AS3 are limited and even troublesome. Here are some circumstances that EventDispatchers turn against developers:
  1. Objects MUST extend EventDispatcher in order to be able to dispatch events. Implementing IEventDispatcher alone is impossible because the event target is read-only and you cannot change it from outside of EventDispatcher.
  2. It’s difficult to manage events. There’s no way you can remove all event handlers attached to an event dispatcher at once. So in some cases, you don’t remove them properly and they start causing bugs. (BTW, using weak references is not reliable and not recommended.)
  3. You cannot pass extra data to you listener unless you extends a new Event object
  4. You cannot set up your interface in a way that it can enforce implementing classes to dispatch the required events.
  5. On performance perspective, creating objects is one of the most evil things. That’s why any advanced programmers must know and practically use objects pool. However, we are still wasting a lot of resources creating event objects, especially repetitive events like mouse move or enter frame.
  6. Read here for more critiques on AS3 events
So in order to address those issues, Robert Penner has adopted an alternative to AS3 events namely as3signals. (Follow the link for more info and get the library)
Here’s the briefing from as3signals wiki page:
Signals: Think Outside the Event.
Signals are light-weight, strongly-typed AS3 messaging tools.
Wire your application with better APIs and less boilerplate than AS3 Events.
  • A Signal is essentially a mini-dispatcher specific to one event, with its own array of listeners.
  • A Signal gives an event a concrete membership in a class.
  • Listeners subscribe to real objects, not to string-based channels.
  • Event string constants are no longer needed.
  • Signals are inspired by C# events and signals/slots in Qt.
Let’s see how as3signals gains advantages over AS3 events:

1. Any object can dispatch events

Here’s how you create an event dispatching object with Signals:
  1. import org.osflash.signals.Signal;
  2. public class Radio {
  3.     // This is the public API to which listeners subscribe.
  4.     public var messageChanged:Signal;
  5.     private var _message:String;
  7.     public function Radio() {
  8.         // Create a Signal that dispatches a String.
  9.         messageChanged = new Signal(String);
  10.     }
  12.     public function get message():String { return _message; }
  14.     // The setter uses the Signal to dispatch the changed value.
  15.     public function set message(value:String):void {
  16.         _message = value;
  17.         messageChanged.dispatch(_message);
  18.     }
  19. }
Here’s how you add event listeners:
  1. var radio: Radio = new Radio();
  2. // Hook the listener up to the Radio's Signal.
  3. radio.messageChanged.add(messageChangedHandler);
  4. function messageChangedHandler(message: String): void {
  5.     trace("heard message: " + message);
  6. }

2. With signals, managing events is much less hassle

You can remove all event handlers with one convenient method:
You can retrieve number of listeners:
You can add a listener that will be removed automatically after just one event:
signal.addOnce(theListener); // result: signal has one listener
signal.dispatch(theEvent);   // result: theListener is called, signal now has no listeners

3. You can dispatch with any number of arguments to listener

You can define types for your arguments
// A Signal that will dispatch a String and an integer:
progress = new Signal(String, int);
Later on, when you dispatch events, as3signals can detect and notify argument error
progress.dispatch(); // will throw ArgumentError
progress.dispatch('The Answer'); // will throw ArgumentError
progress.dispatch('The Answer', 42.5); // will throw ArgumentError
progress.dispatch('The Answer', 42); // will succeed
When adding listeners, they are all so checked for argument types.

4. It’s possible that you enforce events in interface

To see an example, please follow this link http://snipt.org/wSm

5. It’s performance gain because no event object is created in Signals

But that’s not everything yet. The ultimate deal is to replace ENTER_FRAME event.
As we know that ENTER_FRAME event is the key to time-based animations and are widely used. Normally, ENTER_FRAME event can create 25 – 30 objects per second, that’s 1500-1800 objects per minute. But we are aware that that creating objects is evil. So some guys have tried to replace the ENTER_FRAME event with Signals. Read this blog for more info. (The site is currently down, so please use this cache from Google)

6. Signals only projects

Signals can wrap the native events of AS3 so that the whole project will use a consistent messaging system for communication between components. For example:
var click:NativeSignal = new NativeSignal(this, MouseEvent.CLICK, MouseEvent);
The author also claimed that he’s experimenting the bubble feature (the ability to forward events among objects in display list).


It is still under development and improvement but as3signals’ current feature set can satisfy most common project’s needs. Some guys even love it so much that they branch some frameworks to work purely with Signals, for example:
For now, I see no shortcomings of signals but I’m still skeptical that there might be some disadvantages compared to AS3 events because nothing is perfect. (Please help me pointing them out)
Anyway, it is worth trying as3signals in my upcoming projects to see if it really ‘shines’ in real applications.
(Credit: some of the sample code are revised from this Hello World example)
[Vietnamese tags: as3signals: cách tiếp cận mới cho sự kiện (event) trong AS3]

1 comment:

  1. AS3-Signals is great.

    Here is a slideshow, GIT Code Sample, and screencast video about the fantastic AS3-Signals.