Skip to content

Instantly share code, notes, and snippets.

@fatihacet
Created October 15, 2011 22:02
Show Gist options
  • Save fatihacet/1290216 to your computer and use it in GitHub Desktop.
Save fatihacet/1290216 to your computer and use it in GitHub Desktop.
Simple PubSub implementation with JavaScript - taken from Addy Osmani's design patterns book -
var pubsub = {};
(function(q) {
var topics = {}, subUid = -1;
q.subscribe = function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
};
q.publish = function(topic, args) {
if (!topics[topic]) {
return false;
}
setTimeout(function() {
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
}, 0);
return true;
};
q.unsubscribe = function(token) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return false;
};
}(pubsub));
@galcyurio
Copy link

some questions here!
If my thought was wrong, please tell me.
I am new to javascript!

https://gist.github.com/fatihacet/1290216#file-pubsub-simple-js-L17-L27

  1. I think it could be more simpler.
var subscribers = topics[topic];
if (!subscribers) {
    return false;
}

setTimeout(function(){
    for(var i=0, len = subscribers.length; i<len; i++) {
        subscribers[len].func(subscribers, args);
    }
}, 0);

https://gist.github.com/fatihacet/1290216#file-pubsub-simple-js-L34
2. and this conditional statement looks like unnecessary

https://gist.github.com/fatihacet/1290216#file-pubsub-simple-js-L22
3. also I can't understand why he used conditional statement here.
Is it unnecessary that we checked the conditional statement for undefined from the top?

ps. thank you for nice implementation. It was really helpful.

@scazzy
Copy link

scazzy commented Jul 31, 2018

While above is good, and it's crazily 7 years old. I try below method. Instead of using an array, I use an object for each subscriptions as well. Simpler and smaller Also note the unsubscribe closure return in publish, kinda helps.

PubSub.js

class PubSub {
  constructor () {
    this.subIds = 0;
    this.subscriptions = {}
  }
  
  subscribe (topic, fn) {
    if(!this.subscriptions[topic]) this.subscriptions[topic] = {}
    const token = ++this.subIds;
    // Validate topic name and function constructor
    this.subscriptions[topic][token] = fn;
    
    return () => this.unsubscribe(topic, token)
  }
  
  publish (topic, ...args) {
    const subs = this.subscriptions[topic];
    if(!subs) return false
    Object.values(subs).forEach(sub => sub(...args))
  }
  
  unsubscribe (topic, token) {
    if(!token) delete this.subscriptions[topic]; // Delete all subscriptions for the topic
    this.subscriptions[topic] && (delete this.subscriptions[topic][token]); // Delete specific subscription
  }
}

export default new PubSub();

Example

const unsub1 = PubSub.subscribe('spacex', data => console.log('Falcon was launched', data));
const unsub2 = PubSub.subscribe('spacex', data => console.log('Falcon Heavy was launched', data));
PubSub.publish('spacex', 'some data slash params')

// Unsubscribe single subscription
unsub1(); // Unsubscribes Falcon
unsub2(); // Unsubscribes Falcon Heavy

// Unsubscribe ALL subscriptions for a topic
PubSub.unsubscribe('spacex')

@ChiragMDave
Copy link

This isn't publish subscribe pattern, this is the simplest observer pattern.

@hidaytrahman
Copy link

How can I use this as a subscriber

@FirstVertex
Copy link

@scazzy thank you it's precisely what i needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment