RxJS based Pub/sub Eventing

An global eventing system is a pretty key piece of a full fledged MVC app. It lets you very easily separate concerns while maintaining communication between discrete parts of the application.

I’ve been using a simple event dispatcher for a while now. At the same time, I’ve had my eye on the excellent, and still way over my head, RxJS library. I had been using it for DOM / browser events, but I couldn’t wrap my head around how to connect event strings (“magic strings”) with an Observable and use that to execute commands or callbacks. Then I discovered this bit of sample code that demonstrated exactly what I wanted to do.

I hand’t looked at the Subject object before, but it does exactly what I need. And the callback / handler / command execute function fit right into the role of the subscribed onNext function.

Adapting the emitter example fit into my framework was straight forward and I ended up with a new Emitter module that replaces both my old EventDispatcher and EventCommandMap.

I’m keeping a simple map of subjects keyed to the event string

_subjectMap[evtStr] = {
 once: once,
 handler: handler,
 subject: new Rx.Subject()
 };

And whenever an event is published, this object is retrieved and the subject’s subscribers are notified. If the event was only supposed to occur once, it’s unmapped safely.

function publish(evtStr, data) {
  var subjObj = _subjectMap[evtStr];

  if(!subjObj) {
    return;
  }

  if(subjObj.once) {
    subjObj.subject.onCompleted();
    subjObj.subject.dispose();
    subjObj = null;
  }
}

Mapping to a command module was painless as well since we just need to map the execute() function to the subject.

function subscribeCommand(evtStr, cmdModule, once) {
  var cmd = require(cmdModule);
  if(cmd.hasOwnProperty('execute')) {
    return subscribe(evtStr, cmd.execute, once);
  } else {
    throw new Error('Emitter cannot map '+evtStr+' to command '+cmdModule+': must have execute()');
  }
}

Leave a Reply