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()');
  }
}

Adding routes

I had a new JS project come up at work, so I’m taking time to extract my framework from the Gallery project into one that’s reusable for other projects. I should come up with a hipster name for it I suppose. Anyway, I put it on Github as App-Framework.

The Gallery didn’t need to manage multiple views and the URL routes were for  bookmarking to search results. I needed to extend my simple URL router module so that I could bind a controller function to a route change. Since I’d never done this or used a framework that did, this great post gave me a nudge in the right direction.

Setting up a route with the updated router module is pretty simple.

_router.when('/',{templateID:'test', controller:function(obj) {
  console.log('Running route: '+obj.route+', with template: '+obj.templateID);
}});

The when method will map the route (as a key/object property) to a controller function that’s run when the URL changes. Pretty handy.

My app framework utilizes commands for controller functions, so I needed create and addition utility function on my controller to map this to a command:

function mapRouteCommand(route, templateID, command) {
  _router.when(route,{templateID:templateID, controller:function executeRouteCommand(dataObj) {
    command.execute(dataObj);
  }});
}

Mapping is still simple:

mapRouteCommand('/', 'defaultView', _self.RouteInitialViewCommand);
mapRouteCommand('/1', 'test1', _self.RouteOneViewCommand);

From this point, it will call a method in the AppView to load/render/show the view.

Better Modules: Hacking my way towards modularity

“A beginning programmer writes her programs like an ant builds her hill, one piece at a time, without thought for the bigger structure. Her programs will be like loose sand. They may stand for a while, but growing too big they fall apart.

Realizing this problem, the programmer will start to spend a lot of time thinking about structure. Her programs will be rigidly structured, like rock sculptures. They are solid, but when they must change, violence must be done to them.

The master programmer knows when to apply structure and when to leave things in their simple form. Her programs are like clay, solid yet malleable.”

Master Yuan-Ma, The Book of Programming

 

After implementing the automatic namespace import thing the other day, I wasn’t happy that I needed something this like this in the first place. Locking everything behind a rigid namespace was prohibiting reusability. I trying to move forward, but my structure was getting in the way. I’m at the middle paragraph in the quote above.

I wanted to move towards something akin to AMD or CommonJS modules, but I didn’t want to add the additional complexity of a packaging system (Browserify, Webpack, etc.) to my build process (*Why? See below …). I also wanted to know more about how they worked once all of the files are packed in a big file at the end of the process.

The Modules chapter of the Eloquent JavaScript book was a perfect place to start with this. It breaks down the logic and creation of both CommonJS and AMD modules as well as providing basic require() and define() functions. Cujujs.com provides a more insight to how CommonJS modules work in practice also.

Ben Clinkinbeard wrote a great post explaining what the other end of Browserify looks like – how it packages all of the external files together in to one big IIFE and then pulls them out again.

With that, I wrote my own little module system – trying to follow what I was learning about CommonJS. I don’t want to lazy load all of the files so I chose to use a module ID. I’m still using my namespaces for this – it helps to keep them organized in a logical way. At least in my head.

A module skeleton

define('package.moduleID',
  function(require, module, exports){
    exports.myMethod = function() {};
  });

All of the code for the modules is wrapped in a function. I’m passing in the global require function and the module and exports objects. The require() function handles that (below).

The define() function was borrowed from AMD, but it’s much simpler. It stores the modules function code in an object under the ID:

function define(id, moduleCode) {
  if(id in define.cache) {
    return;
  }
  define.cache[id] = moduleCode;
}
define.cache = Object.create(null);

“Loading” a module is straight forward:

var _DOMUtils = require('nudoru.utils.DOMUtils');

The require() function looks up the ID from the define.cache, creates the exports and module objects and invokes the code. It’s also cached for performance later. The returned module is a singleton, having been cached for later use after it’s first instantiated.

function require(id) {
  if (id in require.cache) {
    return require.cache[id];
  }

  var moduleCode = define.cache[id],
      exports = {},
      module = {exports: exports};

  if(!moduleCode) {
    throw new Error('Require: module not found: "'+id+'"');
  }

  moduleCode.call(moduleCode, require, module, exports);
  require.cache[id] = module.exports;
  return module.exports;
}
require.cache = Object.create(null);

I created requireCopy() function that returns an uncached instance of the module. I’m using it for my menus when I need several unique instances of a module – one for each item.

I’m spent a few hours today refactoring my utility classes all of my components with this pattern. It’s testing out well and the resulting code is a lot cleaner. At this point, I’m not quite sure if I’m going to refactor the actual application code … But maybe I’ll feel differently on Monday.

Many thanks to Dustan Kasten for guidance on all of these module systems!

Why am I avoiding packaging?

I’m trying to keep the concat’d JavaScript file as human editable as possible. I want other people to be able to edit my code without needing to install a suite of build tools – something likely to be difficult for most people where I work.

A Tangent

While trying to figure out a problem I did something interesting in the requireCopy() function. Instead of just pulling the instance from the define cache, I created a whole new copy it with some string manipulation. I was interesting in that it did work fine, but it didn’t solve my problem so I removed it.

var funcBody = srcFunc.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1],
newFuncCode = new Function('require, module, exports', funcBody);

Manipulating the function body as plain text has some interesting possibilities. It might be possible to regex the var = require() statements and make a map or perform some light dependency injection.

 

Namespacing Javascript Code for Great Good

Edit This didn’t last long! A day after posting this, I moved to a better, clearer, more modular pattern.

 

I kept my code nice and tidy while developing my app by using proper namespacing to keep it all organized under sane objects. For objects that I want to be global, I’m borrowing from Objective-C and using prefixes, so NObjThingy.

As I’m going back and fixing broken windows, I’ve taken my utility classes out of the global space and put them behind a nudoru.util.* which is great and all, but now using them is ugly

nudoru.util.ObjectUtils.method('foo');

Back in AS3 land, there was true importing of other classes. Once imported, you could access their methods cleanly. I wanted something like that.

I wrote a simple function that basically does that.

function NImport(context, libArry) {
  libArry.forEach(function(lib) {
    var parts = lib.split('.'),
      obj = parts[parts.length-1];
    context[obj] = eval(lib);
  });
}

Usage is simple

NImport(this, ['nudoru.utils.NLorem']);

Accessing also

console.log('lorem: '+this.NLorem.getText(3,5));

This approach has speed advantages since we they’re local variables and we don’t have to look them up. The usage of eval() is dirty, but it works out really well in this case.

Any thoughts on this approach? It’s solving an immediate problem for me, but has anyone else done this differently?