Skip to content

Commit

Permalink
faster, better
Browse files Browse the repository at this point in the history
  • Loading branch information
E.Azer Koçulu committed Jan 15, 2014
1 parent 25193c8 commit 199573f
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 192 deletions.
206 changes: 86 additions & 120 deletions index.js
@@ -1,146 +1,112 @@
module.exports = PubSub;
module.exports = n;

function PubSub(mix){
function n (mix) {
var subscribers;
var subscribersForOnce;

var proxy = mix || function pubsubProxy(){
arguments.length && sub.apply(undefined, arguments);
};
mix || (mix = function (fn) {
if (fn) mix.subscribe(fn);
});

function sub(callback){
subscribe(proxy, callback);
}
mix.subscribe = function (fn) {
if (!subscribers) return subscribers = fn;
if (typeof subscribers == 'function') subscribers = [subscribers];
subscribers.push(fn);
};

function subOnce(callback){
once(proxy, callback);
}
mix.subscribe.once = function (fn) {
if (!subscribersForOnce) return subscribersForOnce = fn;
if (typeof subscribersForOnce == 'function') subscribersForOnce = [subscribersForOnce];
subscribersForOnce.push(fn);
};

function unsubOnce(callback){
unsubscribeOnce(proxy, callback);
}
mix.unsubscribe = function (fn) {
if (!subscribers) return;

function unsub(callback){
unsubscribe(proxy, callback);
}
if (typeof subscribers == 'function') {
if (subscribers != fn) return;
subscribers = undefined;
return;
}

function pub(){
var args = [proxy];
Array.prototype.push.apply(args, arguments);
publish.apply(undefined, args);
}
var i = subscribers.length;

proxy.subscribers = [];
proxy.subscribersForOnce = [];
while (i--) {
if (subscribers[i] && subscribers[i] == fn){
subscribers[i] = undefined;
return;
}
}
};

proxy.subscribe = sub;
proxy.subscribe.once = subOnce;
proxy.unsubscribe = unsub;
proxy.unsubscribe.once = unsubOnce;
proxy.publish = pub;
mix.unsubscribe.once = function (fn) {
if (!subscribersForOnce) return;

return proxy;
}
if (typeof subscribersForOnce == 'function') {
if (subscribersForOnce != fn) return;
subscribersForOnce = undefined;
return;
}

/**
* Publish "from" by applying given args
*
* @param {Function} from
* @param {...Any} args
*/
function publish(from){
var i = subscribersForOnce.length;

var args = Array.prototype.slice.call(arguments, 1);
while (i--) {
if (subscribersForOnce[i] && subscribersForOnce[i] == fn){
subscribersForOnce[i] = undefined;
return;
}
}
};

if (from && from.subscribers && from.subscribers.length > 0) {
from.subscribers.forEach(function(cb, i){
if(!cb) return;
mix.publish = function () {
var params = arguments;
var i, len;

try {
cb.apply(undefined, args);
} catch(exc) {
setTimeout(function(){ throw exc; }, 0);
}
});
}
if (subscribers && typeof subscribers != 'function' && subscribers.length) {
i = -1;
len = subscribers.length;

var callbacks;
if (from && from.subscribersForOnce && from.subscribersForOnce.length > 0) {
callbacks = from.subscribersForOnce.splice(0, from.subscribersForOnce.length);
callbacks.forEach(function(cb, i){
if(!cb) return;
while (++i < len) {
if (!subscribers[i] || typeof subscribers[i] != 'function') continue;

try {
subscribers[i].apply(undefined, params);
} catch(err) {
setTimeout(function () { throw err; }, 0);
}
};
} else if (typeof subscribers == 'function') {
try {
cb.apply(undefined, args);
} catch(exc) {
setTimeout(function(){ throw exc; }, 0);
subscribers.apply(undefined, params);
} catch(err) {
setTimeout(function () { throw err; }, 0);
}
});
delete callbacks;
}

}

/**
* Subscribe callback to given pubsub object.
*
* @param {Pubsub} to
* @param {Function} callback
*/
function subscribe(to, callback){
if(!callback) return false;
return to.subscribers.push(callback);
}


/**
* Subscribe callback to given pubsub object for only one publish.
*
* @param {Pubsub} to
* @param {Function} callback
*/
function once(to, callback){
if(!callback) return false;

return to.subscribersForOnce.push(callback);
}

/**
* Unsubscribe callback to given pubsub object.
*
* @param {Pubsub} to
* @param {Function} callback
*/
function unsubscribe(to, callback){
var i = to.subscribers.length;

while(i--){
if(to.subscribers[i] && to.subscribers[i] == callback){
to.subscribers[i] = undefined;

return i;
}
}

return false;
}

if (subscribersForOnce && typeof subscribersForOnce != 'function' && subscribersForOnce.length) {
i = -1;
len = subscribersForOnce.length;

/**
* Unsubscribe callback subscribed for once to specified pubsub.
*
* @param {Pubsub} to
* @param {Function} callback
* @return {Boolean or Number}
*/
function unsubscribeOnce(to, callback){
var i = to.subscribersForOnce.length;
while (++i < len) {
if (!subscribersForOnce[i] || typeof subscribersForOnce[i] != 'function') continue;

while(i--){
if(to.subscribersForOnce[i] && to.subscribersForOnce[i] == callback){
to.subscribersForOnce[i] = undefined;
try {
subscribersForOnce[i].apply(undefined, params);
} catch(err) {
setTimeout(function () { throw err; }, 0);
}
};

return i;
subscribersForOnce = undefined;
} else if (typeof subscribersForOnce == 'function') {
try {
subscribersForOnce.apply(undefined, params);
} catch(err) {
setTimeout(function () { throw err; }, 0);
}
subscribersForOnce = undefined;
}
}
};

return false;
return mix;
}
27 changes: 27 additions & 0 deletions perf.js
@@ -0,0 +1,27 @@
var pubsub = require('./');

it('subscribes and publishes', function(done){
var foo = pubsub();

foo.subscribe(function () { done(); });

foo.publish(3, 1, 4);
});

it('adds multiple subscriptions', function(done){
var foo = pubsub();

foo.subscribe(function () {});
foo.subscribe(function () {});
foo.subscribe(function () { done(); });

foo.publish(3, 1, 4);
});

it('subscribes and unsubscribes', function(){
var foo = pubsub();
foo.subscribe(foo);
foo.unsubscribe(foo);

function foo () {}
});

0 comments on commit 199573f

Please sign in to comment.