vp-pubsub

    1.0.8 • Public • Published

    NPM

    VP PubSub

    VP PubSub is a publish/subscribe library that supports message filtering

    Index

    Getting Started

    Install

    bower

    bower install vp-pubsub --save-dev

    npm

    npm install vp-pubsub

    git

    git clone https://github.com/schubergphilis/vp-pubsub.git

    Include

    Basic

    <script type="text/javascript" src="vp-pubsub.js"></script>

    AMD

    define(['/bower_components/vp-pubsub/vp-pubsub'], function (PubSub) {
     
    })

    nodejs

    var PubSub = require('vp-pubsub');

    Testing

    Install

    npm

    1. npm install
    2. npm test

    browser

    1. bower install
    2. open test/index.html in the browser

    API

    Event names have some restrictions.

    • The event name is only allowed to use lowercase characters and numbers
    • The first character must be a-z
    • you can use a '.' to name space the event

    Example of valid event names

    • x
    • somelongname
    • a123
    • x.x
    • x.x.x.x.x.x

    Example of invalid event names

    • 1a
    • a.
    • a#$

    pub

    VPpubsub.pub publish a event

    Parameters:
    Name Type Description
    evnt string The event that you want to publish
    [data] * Data that you want to send along with the event
    [scope] * Event scope
    [notAsync=false] boolean Events are default asynchronous, but in some cases yo don't want that
    Example
    //publish an event without data
    VPpubsub.pub('foo');
    //publish an event with `true` as data
    VPpubsub.pub('foo', true);
    //publish a event with `"test"` as data in the scope `window`
    VPpubsub.pub('foo', "test", window);
    //publish a event with `"test"` as data in the scope `window`, synchronise
    VPpubsub.pub('foo', "test", window, true);

    sub

    VPpubsub.sub Subscribe to a event

    You can subscribe to multiple events by separating the event with |. You can subscribe to event in the same namespace by using * (channel filter). example: foo.* will trigger the subscriber by the event foo but also every event that starts with the name space foo like foo.bar

    You can subscribe to all events with *

    Parameters:
    Name Type Description
    evnt string The event(s) where you want to subscribe to.
    subscriber function The subscriber
    [scope] * Scope can be used to only subscribe to events that are in that scope
    [thisArg] * The this scope of the subscriber
    Subscriber parameters
    Name Type Description
    data * The data send by publishing the event
    event string the event that was published.
    $$sub function the subscriber self
    Example
    //only subscribe to foo
    VPpubsub.sub('foo', function (data, evnt, $$sub) {
        console.log(data, evnt, $$sub);
    });
    //subscribe to name space foo
    VPpubsub.sub('foo.*', function (data, evnt, $$sub) {
        console.log(data, evnt, $$sub);
    });
    //subscribe to name space foo.bar
    VPpubsub.sub('foo.bar', function (data, evnt, $$sub) {
        console.log(data, evnt, $$sub);
    });
    //subscribe to foo.bar in the scope window
    VPpubsub.sub('foo.bar', function (data, evnt, $$sub) {
        console.log(data, evnt, $$sub);
    }, window);
    //subscribe to foo.bar and execute the subscriber in the window scope
    VPpubsub.sub('foo.bar', function (data, evnt, $$sub) {
        console.log(data, evnt, $$sub);
    }, null, window);
    //subscribe to all events
    VPpubsub.sub('*', function (data, evnt, $$sub) {
        console.group(evnt);
        console.info(data);
        console.log($$sub);
        console.groupEnd();
    });

    on

    VPpubsub.on works almost the same as VPpubsub.sub but returns a thenable object

    Parameters:
    Name Type Description
    evnt string The event(s) where you want to subscribe to.
    [scope] * Scope can be used to only subscribe to events that are in that scope
    [thisArg] * The this scope of the subscriber

    It will return an object with 2 methods then and off

    then

    VPpubsub.on.then will run the on fulfill function when the subscribed event is published, it will have the same parameters as the subscriber of VPpubsub.sub

    then will return not return a thenable object, it will only return a object with a off method that can be used to unsubscribe. important the off method that the then method returns will only unsubscribe after at least the on fullfill function is called once!

    Parameters:
    Name Type Description
    fulfill function on fulfill function see for the parameters VPpubsub.sub
    off

    VPpubsub.on.off can be used to unsubscribe from the current event

    important to know is that you can't unsubscribe using you on fulfill method like:

    function sub(data) {
        console.log(data)
    }
    VPpubsub.on('test.on');
    .then(sub);
     
    VPpubsub.unsub('test.on', sub);

    Best way to unsubscribe is by using off or using the $$sub inside the on fulfill method

    Example
    //normal use
    VPpubsub
    .on('test.on.api')
    .then(function (data) {
        console.log(data)
    });
     
    //multi times calling then
    var test = VPpubsub.on('test.on.api2')
    //then 1
    test.then(function (data) {
        console.log('called then 1', data);
    });
    //then 2
    test.then(function (data) {
        console.log('called then 2', data);
    });
     
    //subonce
    VPpubsub
    .on('test.on.api.once')
    .then(function (data) {
        console.log(data)
    })
    .off();
     
    //unsub
    var tst2 = VPpubsub
        .on('test.on.api.unsub');
    tst2.then(function (data) {
        console.log(data)
    })
    tst2.off();
    //unsub option 2
    var tst3 = VPpubsub
        .on('test.on.api.unsub')
        .then(function (data) {
            console.log(data)
        });
    //important this will only unsubscribe if at least once the on fulfill function is called
    tst3.off();
    //promise
    var e = VPpubsub.on('test.on.api.promise'),
        p = Promise.resolve(p);
    //important promise will only return the data not the event or subscriber
    p.then(function (data) {
        console.log(data)
    })
    .then(function (data) {
        e.off();
    });
     

    subonce

    VPpubsub.subonce same as sub only it will subscribes once to the event, with on limitation you can not subscribe to a channel (*)

    unsub

    VPpubsub.unsub unsubscribe from a event

    Event, subscriber and scope must be the same as when you subscribed.

    Parameters:
    Name Type Description
    evnt string Event where from you want to unsubscribe
    subscriber function The subscriber
    [scope] * the scope if used by subscribing

    fork

    VPpubsub.fork returns a VPpubsub with his own subscribers

    Tips

    Unique events

    Problem

    If you've a set up as bellow, than module A and module B will always have the result of both request and that is probably not what you want.

    //module A
    VPpubsub.sub('message.result', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get', {
        type: 'error'
    });
     
    //module B
    VPpubsub.sub('message.result', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get');
     
    //module log message
    VPpubsub.sub('message.result', function (result) {
        console.log(result)
    })
     
    //module Message
    VPpubsub.sub('message.get', function (filter) {
        VPpubsub.pub('message.result', [])
    })

    Solution 1 ( channels )

    One way to fix this is to use the channel filter as used below.

    //module A
    VPpubsub.sub('message.result.moduleA', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get.moduleA', {
        type: 'error'
    });
     
    //module B
    VPpubsub.sub('message.result.moduleB', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get.moduleB');
     
    //module log message
    VPpubsub.sub('message.result.*', function (result) {
        console.log(result)
    })
     
    //module Message
    VPpubsub.sub('message.get.*', function (filter, evnt) {
        var id = evnt.split('.').splice(2).join('.'),
            resultEvent = 'message.result';
        if (id) {
            resultEvent += '.' + id;
        }
        VPpubsub.pub(resultEvent, [])
    })

    Solution 2 ( ID's )

    Another way to fix this is to use event ID's. You can subscribe and publish an event with a ID. Subscribers that are subscripted to events with a ID will only be triggered if the ID match, all other subscribers for that event, include channel subscribers will be triggered normally.

    You can give an event a ID via adding a @ to the event name for example message.get@myid. a Event ID can only exists of 0-9 and a-z characters. To give a example of when what is triggered

    - publish without ID
    pub: message.get
    sub: message.get        //triggered
    sub: message.get@myid   //not triggered
    sub: message.get.*      //triggered
    - publish with ID
    pub: message.get@myid
    sub: message.get        //triggered
    sub: message.get@myid   //triggered
    sub: message.get.*      //triggered
    

    the solution with id would like this

    //module A
    VPpubsub.sub('message.result@moduleA', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get@moduleA', {
        type: 'error'
    });
     
    //module B
    VPpubsub.sub('message.result@moduleB', function (result) {
        console.log(result)
    })
    VPpubsub.pub('message.get@moduleB');
     
    //module log message
    VPpubsub.sub('message.result', function (result) {
        console.log(result)
    })
     
    //module Message
    VPpubsub.sub('message.get', function (filter, evnt) {
        var id = evnt.split('@')[1],
            resultEvent = 'message.result';
        if (id) {
            resultEvent += '@' + id;
        }
        VPpubsub.pub(resultEvent, [])
    })

    is published ?

    Problem

    If you've a set up as bellow, than event module.a.api will never be published because event module.a.ready was already published before module B was subscribing on it.

    //module A
    define('module/a', ['vp-pubsub'], function (PubSub) {
        PubSub.sub('module.a.api', function (data) {
            console.log(data)
        })
        PubSub.pub('module.a.ready');
    });
     
    //module B
    define('module/b', ['vp-pubsub'], function (PubSub) {
        PubSub.subonce('module.a.ready', function () {
            PubSub.pub('module.a.api', {filter: 1});
        })
    });
     
    require(['module/a', 'module/b'])

    Solution 1 ( multiple events )

    One way to fix this is to introduce a extra event where you request of the module is ready that then re-publish the ready event. In this way it does not matter of module A or module B is first loaded.

    - first load module A
    loading module A (pub: module.a.ready) > loading module B > pub: module.a.isready > pub: module.a.ready > pub: module.a.api
    - first load module B
    loading module B (pub: module.a.isready) > loading module A > pub: module.a.ready > pub: module.a.api
    
    //module A
    define('module/a', ['vp-pubsub'], function (PubSub) {
        PubSub.sub('module.a.api', function (data) {
            console.log(data)
        });
        PubSub.sub('module.a.isready', function () {
            PubSub.pub('module.a.ready');
        });
        PubSub.pub('module.a.ready');
    });
     
    //module B
    define('module/b', ['vp-pubsub'], function (PubSub) {
        PubSub.subonce('module.a.ready', function () {
            PubSub.pub('module.a.api', {filter: 1});
        })
        PubSub.pub('module.a.isready');
    });
     
    require(['module/a', 'module/b'])

    Solution 2 ( force publishing last data )

    Another way to fix this is to use the force publishing last data API. VP PubSub will always remember the last published data of a event. You can request the last published data via adding a ! at the front of the event name. For example: !module.a.ready. Keep in mind that it only remembers the last published data, so this works great with ready events or events that contains counter data

    //module A
    define('module/a', ['vp-pubsub'], function (PubSub) {
        PubSub.sub('module.a.api', function (data) {
            console.log(data)
        });
        PubSub.pub('module.a.ready');
    });
     
    //module B
    define('module/b', ['vp-pubsub'], function (PubSub) {
        PubSub.subonce('!module.a.ready', function () {
            PubSub.pub('module.a.api', {filter: 1});
        });
    });
     
    require(['module/a', 'module/b'])

    Install

    npm i vp-pubsub

    DownloadsWeekly Downloads

    2

    Version

    1.0.8

    License

    Apache License v2.0

    Last publish

    Collaborators

    • victor-perez