📜 ⬆️ ⬇️

Signals again

Translation of the Aiden Tailor article on signals that have migrated to ActionScript from C # through the efforts of Rober Penner . This is not just a translation, but a cheat sheet - squeezing the article. Without water, nothing superfluous, so that even the laziest could run through their eyes. Performance tests are also performed. The post is not only for AS3 gurus, but also for everyone who cares about improving the quality of the code, as it contains a description of one of the implementations of the Observer design pattern. But the video tutorial .

At its core, Signal is a separate event manager with its own array of subscribers. The main idea is to get away from the string comparisons used in EventDispatcher and spawning a set of Events. The as3 sources of the library can be taken from the GIT repository here .

Signal - the main signal.
')
package insideria.basicSignal { import org.osflash.signals.Signal; public class AlarmClock { public var alarm:Signal; public function AlarmClock() { alarm = new Signal(); //   } public function ring():void { alarm.dispatch(); //   () } } } package insideria.basicSignal { import flash.display.Sprite; public class WakeUp extends Sprite { private var alarmClock:AlarmClock; public function WakeUp() { alarmClock = new AlarmClock(); alarmClock.alarm.add(onRing); //   alarmClock.ring(); } private function onRing():void { //  trace("Wake up!"); } } } 


Parameters are passed by listing types in the signal constructor:

  package insideria.basicSignalArguments { import org.osflash.signals.Signal; public class AlarmClock { public var alarm:Signal; public function AlarmClock() { alarm = new Signal(String); //     } public function ring():void { alarm.dispatch("9 AM"); //  } } } package insideria.basicSignalArguments { import flash.display.Sprite; public class WakeUp extends Sprite { private var alarmClock:AlarmClock; public function WakeUp() { alarmClock = new AlarmClock(); alarmClock.alarm.add(onRing); alarmClock.ring(); } private function onRing(time:String):void { //   - ,      trace("Wake up! It's already " + time); } } } 


Garbage Collector eats instances, if unsubscribe (checked personally):

  alarmClock.alarm.remove(onRing); //  alarmClock.alarm.addOnce(onRing); //   , , ,  Event.ADDED_TO_STAGE alarmClock.alarm.removeAll(); //    


DeluxeSignal - the luxurious (extended) signal allows you to access the signal owner and the signal itself.
It can transfer to the listener both a GenericEvent (general event) and custom parameters (as a base signal). Using it is sometimes an unaffordable luxury (see performance tests at the end of the post)

  package insideria.deluxeSignal { import org.osflash.signals.DeluxeSignal; import org.osflash.signals.events.GenericEvent; public class AlarmClock { public var alarm:DeluxeSignal; public var message:String; public function AlarmClock() { alarm = new DeluxeSignal(this); //   target  message = "This is a message from our AlarmClock"; } public function ring():void { alarm.dispatch(new GenericEvent()); //  GenericEvent } } } package insideria.deluxeSignal { import org.osflash.signals.events.GenericEvent; import flash.display.Sprite; public class WakeUp extends Sprite { private var alarmClock:AlarmClock; public function WakeUp() { alarmClock = new AlarmClock(); alarmClock.alarm.add(onRing); alarmClock.ring(); } private function onRing(event:GenericEvent):void { trace(event.target); // target,      trace(event.signal); //  trace(event.target.message); } } } 


NativeSignal is a native signal. Converts native ActionScript events to signals.
Example:
  package insideria.nativeSignals { import org.osflash.signals.natives.NativeSignal; import flash.display.Sprite; import flash.events.Event; public class AddToStage extends Sprite { public function AddToStage() { var added:NativeSignal = new NativeSignal(this, Event.ADDED_TO_STAGE, Event); //      Event' added.addOnce(onAdded); } private function onAdded(event:Event):void { graphics.beginFill(0xCCCCCC); graphics.drawRect(0, 0, 100, 100); graphics.endFill(); } } } 


Performance:

- the profile showed that Signal on average otzhiruet additional 4 KB of RAM per instance compared to EventDispatcher
- Signal is not more than 2 times slower than EventDispatcher
- Deluxe Signal is about 4.5 times slower than EventDispatcher (it is now clear why this is called)
- NativeSignal - not tested, but analysis of the code showed that the performance will be about the same as that of Signal

The code on which the execution speed test was performed:

  public class Main extends Sprite { private static const COUNT:int = 10000; private var _signal: SignalItem; private var _dispatcher: DispatcherItem; private var t:int; private var i:int; private var test:int; public function Main() { _signal = new SignalItem(); _signal.signal.add(onSignal); test = 0; t = getTimer(); for (i = 0; i<COUNT; i++) { _signal.dispatch(); } t = getTimer()-t; trace("Main.Main(); signal : " + t); _dispatcher = new DispatcherItem(); _dispatcher.addEventListener(Event.CHANGE, onChange); test = 0; t = getTimer(); for (i = 0; i<COUNT; i++) { _dispatcher.dispatch(); } t = getTimer() - t; trace("Main.Main(); dispatcher : " + t); } private function onSignal(z:int): void { test++; } private function onChange(e:Event): void { test++; } } public class SignalItem { private var _signal:DeluxeSignal; public function SignalItem() { _signal = new DeluxeSignal(this); } public function get signal(): Signal { return _signal; } public function dispatch():void { _signal.dispatch(new GenericEvent()); } } public class DispatcherItem extends EventDispatcher{ public function DispatcherItem() { } public function dispatch ():void { dispatchEvent(new Event(Event.CHANGE)); } } 


Findings:

In essence, the Signals are the same pattern Observer, that is, an alternative to IEventDispatcher. Performance is lower because the library is not native, but at an acceptable level. Using signals can open a migration of other solutions tied to them, from C # to ActionScript.

A plus:
- more compact code

Minus:
-performance

Source: https://habr.com/ru/post/109376/


All Articles