Signal Emitter
When I released JS-Signals I decided to create a document explaining the difference between different kinds of Observers and the possible pros and cons of each pattern, and as you can see on the document every approach has its pros/cons and depending on the scenario the recommended approach might change.
Before coding JS-Signals I was using a very basic EventEmitter “class” that could be used to listen/dispatch arbitrary events but ever since I released JS-Signals I almost didn’t used arbitrary events anymore (because of the benefits of using a Signal), but a couple weeks ago I had to propagate changes on my model classes to the UI and the changes are coming from many different inputs, so the easiest way to keep everything in sync was to dispatch events every time my model objects updated with a new value. In that case it is way easier to use a string ID for the event type than to create a new Signal object manually for each value, since the project was already using Signals everywhere I decided to code a simple EventEmitter that would use JS-Signals internal mechanism (so I could use the advanced features if needed) but still allow arbitrary event types.
define(['signals'], function (signals) { /** * Signal Emitter * JS-Signals wrapper to convert it into a regular Event Emitter, which can * lister/dispatch arbitrary events. * @author Miller Medeiros * @version 0.1.1 (2012/01/23) * @license WTFPL */ function SignalEmitter(){ this._signals = {}; } var _proto = SignalEmitter.prototype = { addListener : function(id, handler, scope, priority) { if (! this._signals[id]) { this._signals[id] = new signals.Signal(); } return this._signals[id].add(handler, scope, priority); }, removeListener : function(id, handler) { var sig = this._signals[id]; if (! sig) return; sig.remove(handler); }, getSignal : function(id) { return this._signals[id]; }, dispatch : function(id, args) { var sig = this._signals[id]; if (! sig) return; if (args) { sig.dispatch.apply(sig, args); } else { sig.dispatch(); } } }; SignalEmitter.augment = function(target) { SignalEmitter.call(target); for (var key in _proto) { if (_proto.hasOwnProperty(key)) { target[key] = _proto[key]; } } }; return SignalEmitter; });
You can use it as a standalone object:
var obj = new SignalEmitter(); obj.addListener('foo', console.log, console); obj.dispatch('foo', ['bar']);
Or extend an existing object to add the SignalEmitter
behavior to it:
var obj = { doSomething : function(args){ this.dispatch('foo', ['lorem', 'ipsum']); } }; //"inherit" from SignalEmitter object SignalEmitter.augment(obj); obj.addListener('foo', console.log, console); obj.doSomething();
The method addListener
returns a SignalBinding
object and you can also get a reference to the underlaying Signal object by calling getSignal(id)
so you will have access to all the advanced features from JS-Signals while keeping a very flexible structure.
Feel free to remove unneeded features like SignalEmitter.augment()
or getSignal()
, added more as a reference and because on my current project I needed both things.
Very simple code but may be useful to somebody else…
PS: please note that listening/dispatching non-existent events will fail silently (one of the main reasons why I started using Signals), use with care.