PubSub extended with logic keeping a light footprint. Pubsub for modern JS apps is to get out of callback hell - take the subway in a traffic jam.


Have you ever had

  • Code you wanted to only invoke once - but with a message that repeats?
  • Code you wanted to only invoke when a range of messages have all been published (in random order)?
  • Code you wanted to pause invoking at speciffic conditions?

Of cause you have... cause thats what real world code needs.

And everytime you have dealt with it by making some good counters around your pubsub structure and build nicely structured features to take care of when to invoke and when not to.

PubSubway replaces the counters and the logic around your observer pattern with easy to read chuncks of code with a light footprint.

Just take the subway instead of sitting in the trafic jam...

    * Example * 
    var db = require('mysql');
    var go = require('pubsubway');
    var mysql = createConnection(db);
    go.whenAND(['/sql_a/done', '/sql_b/done'], function(){
        console.log('Both SQL a and SQL b are done now');
    mysql.query('UPDATE product SET stock = 7 WHERE id = 423', function(){
    mysql.query('UPDATE product SET stock = 2 WHERE id = 332', function(){

To use in regular browser just include file as normal (Yay!)

    <script src="pubsubway.min.js" type="text/javascript"></script>

In the browser you use the examples with pubsubway.* instead of the go.* - and ignore the 'require' line.


Any involvement in the project is very welcome, and encouraged.

The pubsub pattern

Please remember that the pubsub style of programing (observer pattern) is best suited to publish messages about what has happened. Dont fall into the pifall of using it as regular functions. A good idea is to label your topics in past sense.


You include the module with a traditional var go = require('pubsubway'); or any name you find suitable. In the documentation I chose go cause it short and sounds nice.

Depending on the style of program you are developing I personally prefer either long and javaish style method names or short names that fit into the rest of the code more seamless. Thats why the API comes with a bunch of aliases =
    go.yell =  
    go.publish = function(
                            topic /* string */ 
                            args /* array */

To listen to a single message and invoke code is trivial - but when you want to listen to several messages you are suddenly left with a lot of choises recarding how to handle the logic around it.

    go.sub =
    go.when =
    go.subOR =
    go.whenOR =
    go.subscribe = function(        topic           /* string || array */
                                    callback        /* Function */
                                    subscribeFirst  /* [bool] */
                                    mode            /* string */


    go.subscribe("/foo/bar", function(abc){ 
    go.sub1 =
    go.when1 =
    go.subOR1 =
    go.whenOR1 =
    go.subscribeOnce = function(    topic           /* string || array */
                                    callback        /* Function */
                                    subscribeFirst  /* [bool] */
                                    mode            /* string */
    go.subAND =
    go.whenAND =
    go.subscribeAND =
    go.subscribeANDmodeContinues = function(
                                                topic /* string || array */
                                                callback /* Function */
                                                subscribeFirst /* [bool] */ 
me.subAND1 =
me.whenAND1 = 
me.subscribeANDmodeOnce = function(
                                            topic           /* string || array */
                                            callback        /* Function */
                                            subscribeFirst  /* [bool] */ 
    //ToDo:implement reset
    me.subscribe(topic, callback, subscribeFirst, 'ANDmodeOnce') 

Subscribe to messages but only start invoking each time all of them have been published again.

   go.subREWIND =
   go.whenREWIND =
   go.subscribeREWIND =
   go.subscribeANDmodeRewind = function(
                                           topic             /* string || array */ 
                                           callback          /* Function */
                                           subscribeFirst    /* [bool] */ 

Subscribe to messages but pause and restart with

    go.whenORBUT = 
    go.subORBUT = 
    go.subscribeORmodeButNotIfButResetWith = function(
                                                        topic /* string || array */ 
                                                        butNotIf /* string || array */
                                                        resetWith /* string || array */
                                                        callback /* Function */
                                                        subscribeFirst /* [bool] */

Unsubscribe a subscription

    go.unsub =
    go.unsubscribe = function(handle /* Array */){ 
        //    var handle = pubsubway.subscribe("/foo", function(){});  
        //    pubsubway.unsubscribe(handle);  
        // ToDo: make it possible to resubscribe a handle 
        // ToDo: implement go.subways[uid].handlers check  

Log the publications

   go.log = function(/* string */ msg/* integer */ level){ 
       //  log events -   
       //  Please overwrite behavior with something like 
       //  $.log = function(msg){alert(msg)}  
       if(doLog && level<=100){ 
           console.log('pub/sub: ' + msg); 

Start/stop logging

    go.doLog = function(/*bool*/ val)

Stop all publications

The big handbrake

    go.voidAction = function(/*bool*/ val){ 

Wrap topics

Wrab topics to act like traditional callback function to handle strings as callbacks

    // Make it convinient to publish string instead of sending function as callback  
    // Use in your own funktion like:        
    //      callback_function = go.pubsubBack(topic /* sting */) 
    // to be able to put a function or a string to publish as your own callback  
    go.pubsubBack(topic /* sting */)


  • Tests: The module is used and enchanged in production - so it works, but better get those tests up and running...

  • pubAlert: optional Log warning when something is published that nothing is subscribed to. Good fro development.

  • pubBuffer: Setting to buffer all publications untill released. Good for when you publish things in your sync flow, but want to message something that will be observing a little later caused by async waiting. Is it bad structure of the code? well, if it is used in the main flow it is, but during the initial load of code it is not.

  • Mode strings to mode vars To make the minifyed version smaller all the hardcoded strings for mode should be a variable returned by a function.


License: MIT

Pattern: Observer

Inspiration: Loosely based on jQuery pub/sub plugin by Peter Higgins, expanded in scope. Rewritten blindly.