I am finished with my implementation of PUB/SUB or Observer pattern, however I just want to see any ways that I may be able to improve this pattern. I wanted to be able to use the typical PubSub
pattern except add performance enhancements by using the new key word to instantiate each new instance of a PubSub
object, as well as make sure that the initialize fn as well as all of the public methods are chain-able.
Here is my PubSub definition:
(function(global) {
'use strict';
var newPubSub;
global.PubSub = {
core: function core() {},
init: function(moduleNs) {
if (!global[moduleNs]) global[moduleNs] = new PubSub.core();
else throw new Error('A module has already been initialized under this namespace');
newPubSub = global[moduleNs];
return newPubSub;
}
};
var instance = PubSub.core.prototype;
/**
* Will check for the existance of prev array under this ns and if none exists it will create
* a new prop with the ns and the function as the sole member of the array. If an array already
* exists under this namespace then the function is simply pushed into that namespaces array of
* methods that it will be triggered when that ns becomes published.
**/
instance.sub = function(ns, fn) {
if (!newPubSub[ns]) {
newPubSub[ns] = [fn];
}
else if (Array.isArray(newPubSub[ns]) && newPubSub[ns].length > 0) {
newPubSub[ns].forEach(function(savedFn) {
if (fn === savedFn) throw new TypeError('This function already exists under this namespace, please provide a new method for this namespace or add a new namespace to hold this method/fn');
else {
newPubSub[ns].push(fn);
}
});
}
return this;
};
/**
* Will remove all methods for a listener and the listener ns is not provided,
* or will remove a single method from a listener if the ns provided has a matching method/fn
**/
instance.unsub = function(ns, fn) {
function revokeAllMethods(ns) {
if (newPubSub[ns]) {
delete newPubSub[ns];
}
}
// loops through all the methods in a namespace provided and compares to see if the method provided exists, if it does it will be removed
function revokeSpecificMethod(ns, fn) {
newPubSub[ns].forEach(function(savedMethod, idx) {
// Remove the method that matches the one provided to unsubscribe
if (fn === savedMethod) newPubSub[ns].splice(idx, 1);
// Otherwise an error will be thrown
else throw new Error('No method match found under the namespace '+ns);
});
}
if (typeof ns === 'string') {
if (!fn) {
revokeAllMethods(ns);
}
else if (typeof fn === 'function') {
revokeSpecificMethod(ns, fn);
}
}
return this;
};
/**
* Will trigger an event with provided params on any methods under the ns triggered
*/
instance.pub = function(ns, params) {
if (!newPubSub[ns]) throw new TypeError('No method found under the namespace "' + ns + '" inside of Object. It has either been unsubscribed or never existed.');
newPubSub[ns].forEach(function(fn) {
fn.apply(null, params);
});
return this;
};
})(window);
Implementation:
PubSub.init('test');
test.sub('alert', function(msg){
alert(msg);
}).pub('alert',['bob']).sub('somethingelse', function(){
alert('look ma no params');
}).pub('somethingelse').pub('alert',['bob']).unsub('alert').pub('alert',[12]);