mroderick / pubsubjs Goto Github PK
View Code? Open in Web Editor NEWDependency free publish/subscribe for JavaScript
License: MIT License
Dependency free publish/subscribe for JavaScript
License: MIT License
The link "A Comparison of JS Publish/Subscribe Approaches" is broken. I would be interested in seeing that comparison, if it still exists ...
The try-catch block on line 82 makes it very difficult to determine where errors have occurred as the error stack shows PubSub as the source of the exception.
try {
subscribers[i].func( message, data );
} catch( e ){
setTimeout( throwException(e), 0);
}
Is there a reason why this is in place? Otherwise I would remove it to provide better debugging data to those developing.
Thanks,
Alistair
Hi
Firstly thanks for this great piece of asynchronous code!
Sometimes there is a need to unsubscribe from a message in a callback. At the moment (in some conditions) it triggers an error. Code example:
var mySubscriber = function(msg, data) {
PubSub.unsubscribe(mySubscriber);
console.log('mySubscriber');
};
var mySubscriber2 = function(msg, data) {
console.log('mySubscriber2');
};
PubSub.subscribe( 'MY MESSAGE', mySubscriber);
PubSub.subscribe( 'MY MESSAGE', mySubscriber2);
PubSub.publish( 'MY MESSAGE', 'hello world!' );
BR
I believe that you should incorporate minified version of the library in to repository.
Thanks.
Hi All,
I just ran into an issue where the "modules" global declared by QUnit (which apparently complies with CommonJS) causes PubSub to think a module loading framework is present and take itself out of the global namespace, causing some of my stuff to break.
See this discussion on the QUnit site:
I notice that KnockoutJS uses the following logic for detecting a module loader:
function(factory) {
// Support three module loading scenarios
if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
// [1] CommonJS/Node.js
var target = module['exports'] || exports; // module.exports is for Node.js
factory(target);
} else if (typeof define === 'function' && define['amd']) {
// [2] AMD anonymous module
define(['exports'], factory);
} else {
// [3] No module loader (plain <script> tag) - put directly in global namespace
factory(window['ko'] = {});
}
}
Could someone modify the detection code in PubSub accordingly? Much appreciated (I'll have to do this locally in the meantime).
Cheers, Andrew.
Any reason why:
var PubSub = require('pubsub-js');
PubSub === window.PubSub; // false
I see in the first line of the source file that factory()
is called twice, one for AMD/CommonJS (lines 12 and 16) and one for the browser (line 23). That way the two objects are not the same, and so you cannot use require('pubsub-js')
and window.PubSub
interchangeably.
Isn't possible to make it so, creating a single unique singleton object accross AMD/CommonJS and browser?
I would recommend to pass msg
as a second argument. Because you are supposed to use data
first. And that becomes very annoying to rewrite APIs to skip the msg
argument and to see the editor's highlighting of unused local variable.
So, instead of:
var mySubscriber = function( msg, data ){ // do something with data };
do this:
var mySubscriber = function( data ){ // do something with data };
Isn't it better?
The developer documentation could use some improvements
This seems to be one of the most popular Node pub-sub repos but I see all open PR's are over half a year old and the latest release was almost 1.5 years ago.
Is this being deprecated or are there plans to maintain the package?
Perhaps this is related to (or duplicate of) #32.
It would be great to have an option to unsubscribe all handlers for a given message. This is actually the most common practice in most pubsub implementations, e.g:
subscribe('message', handler); // subscribe handler to 'message'
subscribe('message', anotherHandler); // another handler is subscribed
unsubscribe('message'); // stop all form listening to 'message' event
Moreover, it would be great to be able to use this in conjunction with existing API, to be able to unsubscribe a specific handler from a given message, so that a handler could be used for multiple messages, but easily removed from listening to a single message, without the need for a token.
The need to be able to not use the token is mostly for interoperability, since it's not so common API for other pubsub libraries.
Thanks!
~Y
The problem I'm having is that I want to call a method on a class, and that method references variables with in the class. Currently they are out of scope and return undefined.
This is the basic idea $.pubsub("subscribe", "update_stuff", callbackFunc, scopeOfCallBackFunc)
Is it currently possible to do something like this? Any recommendations?
I have came across a potential memory leak in this scenario:
Frameset page that hosts PubSub
Frame 1 loads page 1, and connects to the PubSub on the frameset
window.PubSub = top.PubSub;
Frame 2 loads page 2 and connects to PubSub on the frameset
window.PubSub = top.PubSub;
the frames can now send messages to one another without any problem
now Frame 1 loads page 3 that connects to the PubSub on the frameset but without page 1 unsubscribing first.
Now when frame 2 tries to send a message to frame 1 there are actually two listeners in the delivery: 1 and 3. When delivery is attempted to 1 weird things happen:
on FF it passes without any exception but nothing actually happens
on IE an exception is thrown -2146823277 “Can't execute code from a freed script”. When inspecting the code the function pointer is still there with all code so actually the DOM is still held for the page. the reason for this error according to some posts online is that the window hosting the script has been closed/removed (which is correct as the frame contents has been replaced)
obviously if a lot of pages subscribe but never unsubscribe before being replaced there will be a big memory leak. My suggestion for a fix (which will work on IE at least) is to catch the specific exception -2146823277 when trying to invoke the subscriber and if caught remove the subscriber from the list of subscribers.
I am not sure how the same could be done on FF/Chrome as they do not throw an exception and I have not found a way to check if the window is still alive (except maybe when subscribing provide the window object the function is on and then check if that object is still alive or not)
This will enable publisher to go to idle state and save resources when there are no subcribers.
Radio allows you specify the context for a registered callback, and sets 'this' when executing it. This would be very useful for PubSubJS as well.
Something like
Foo.prototype.init = function() {
this.token = PubSub.subscribe( 'MY TOPIC', this.myCallback, this );
};
Foo.prototype.myCallback = function(msg, data) {
// 'this' should be the Foo instance, but is instead the window object
}
var foo = Foo();
PubSub.publish('MY TOPIC', 'hello world');
It's weired that when i run rake jquery to get a jquery pubsub version.After that, i use it in requriejs version 2.1.8+ where the config is like
requirejs.config({
'paths': {
'jquery': 'jquery-1.10.2.min',
'pubsub': 'jquery.pubsub'
},
'shim': {
'pubsub': ['jquery']
}
});
it produced a error said
PubSub is not defined` in line `pubsub.version = PubSub.name + ' ' + PubSub.version;
It seem that the the line 38
``
if (typeof exports === 'object' && module){
module.exports = factory();
// AMD
} else if (typeof define === 'function' && define.amd){
define(factory);
// Browser
} else {
root.PubSub = factory();
}
How to Use PubSubJS to publish object or array?
It would be awesome to have this on code.jquery.com or some such.
Just wondering about having this published to npm. Had a look there and it looks like the pubsubjs name is taken...any chance of publishing though?
I'm considering this lib vs Subtopic which is one of the many ports of Peter Higgins's script. It's more lightweight and looks like it does support the same features, while only lacking AMD support.
What would be the advantage to use this implementation instead ?
Also, it seems pubsub.js lacks the possibility to pass a scope object along with the published event. is there a particular reason to omit this feature ?
And last, any reason to use a dot as separator instead of slash ?
Thanks
Would it be in the spirit of PubSub to add the ability to capture the return value of subscribers when doing synchronous publishes? Like so:
PubSub.subscribe('event', function(data) {
return 1;
});
PubSub.subscribe('event', function(data) {
return 2;
});
PubSub.subscribe('event', function(data) {
return 3;
});
PubSub.subscribe('event.something', function(data) {
return 4;
});
var results = PubSub.publishSync('event.something', { data: 1 })
> results
> [1, 2, 3, 4]
This does have some use cases, such as in a plugin/hook architecture. A way of doing this currently would be for each subscriber to touch a global variable, which doesn't seem all that nice.
I would suggest
if ( sync === true ){
deliver();
to change to:
if ( sync === true ){
return deliver();
and then each callSubscriber inside of deliverMessage to append to a list and return that, then subsequently deliverMessage to concatenate the lists. Returning an object may be better, with the keys denoting the message name. Eg:
> results
> {
event: [1, 2, 3],
event.something: [4],
}
The signature of .publishSync() would change slightly, but code doing a truthy/falsy check on its current return value (true/false) should still continue to work.
Thoughts?
Two ways to access the PubSub component:
var event2 = new PubSub();
You have to create a subscriber on each of the namespaces from root to the penultimate topic; otherwise it fails on a logical error.
variable found at line 92 is set to true on a parent topic, but the moment that a topic that's closer to root doesn't have a subscribe the found turns to false and that's what is eventually bubbled up. It previously found a matching subscriber and never delivered the message.
This works:
var rootTopic = 'a.b.c';
pubsub.subscribe(rootTopic, function (ev) {
console.log("this happened -> ", ev);
});
pubsub.subscribe('a.b.c', function (ev) {
console.log('this happened --> ', ev);
});
pubsub.subscribe('a.b', function (ev) {
console.log('this happened --> ', ev);
});
pubsub.subscribe('a', function (ev) {
console.log('this happened --> ', ev);
});
pubsub.publish(rootTopic + '.closed');
This doesn’t work:
var rootTopic = 'a.b.c';
pubsub.subscribe(rootTopic, function (ev) {
console.log("this happened -> ", ev);
});
pubsub.publish(rootTopic + '.closed');
Would it be possible to add a check to in the subscribe function that func is actually a function. Currently if func is undefined or not a function the error only occurs when the message is published
PubSub.subscribe = function( message, func )
Or do you think this is necessary/unlikely that is it not worth checking?
Many thanks
.
There seems to be a problem in your jquery version.
I get a "PubSub is not defined" when including it in my project. It seems you dont expose PubSub to the jquery wrapper.
The publish() and publishSync() methods return a boolean. I assume (and I could be wrong as I did not see it documented) this boolean value indicates whether or not there were any subscribers to the topic.
It seems that the publish() [and publishSync()] method returns true if there was ever a subscriber to the topic, regardless of whether such a subscriber currently exists.
Here is an example. After the subscriber removes itself, the publish() method will always still return true.
// Example Code:
function documentReady() {
var unsubscribeToken = PubSub.subscribe('AAA', function (msg, data) {
console.log("Received a published message to the 'AAA' topic...");
// Unsubscribe. There should be no more subscribers, but publish()
// still returns true, forever.
PubSub.unsubscribe(unsubscribeToken);
});
$("#theButton").click(function () {
var pubResult = PubSub.publish('AAA', null);
// IT SEEMS pubResult IS ALWAYS true!!
console.log("After publish, pubResult=" + pubResult);
});
}
jQuery(document).ready(documentReady);
How would you feel for support for wildcards?, e.g:
given:
a.b.d.e
a.b.d.f
a.c.d
a.*.d would subscribe to all 3.
There' s a couple of cases I'm looking at at where having wildcards would solve the usecase of otherwise needing 2 hierarchies to describe the events.
Would this be useful?
The following code works fine in the browser with AMD but doesn't work in Karma test runner:
define(['pubsub'], function (pubsub) {
pubsub.publish('test');
});
In Karma, pubsub is undefined, because it takes the route of common js thinking that module
is defined
// CommonJS
if (typeof exports === 'object' && typeof module !== 'undefined'){
module.exports = factory();
// AMD
} else if (typeof define === 'function' && define.amd){
define(factory);
// Browser
} else {
root.PubSub = factory();
}
Hey there,
I'm considering writing a project specific extension to you package, but before I did, I thought I'd throw the idea your way to see if you'd want to include such a feature.
In a specific scenario, I require to pause the publication of an event while something else happens. I was considering writing a "before" function. It might look something like:
before('someMessage', (message, data, done) => {
// Once "someMessage" is published, none of the subscribers will
// be notified until I call `done()`
doSomethingAsynchronous().then(done);
});
No worries if this is not suitable for your package, but if it is, it would save forking.
Ta.
When using publishSync wouldn't it be better to return as a return value the return value of the subscribed functions chained, instead of the way it is now, where the return value indicates if there are subscribers? . i.e. call all subscribers in a hierarchical order and if the returned value of a subscriber function is true continue with the next subscriber if it is false return false to publishSync. What do you think? Or should we implement a second "publishChainedSync" (or some other better name) ....
Ognian
Does this support pub in one chrome tab and sub in another tab, more can it cross iframe?
The issue can be reproduced as follow:
A = PubSub.subscribe('test', function () { PubSub.unsubscribe(A); console.log('A'); });
B = PubSub.subscribe('test', function () { console.log('B'); });
C = PubSub.subscribe('test', function () { console.log('C'); });
PubSub.publish('test');
Output:
A
C
The problem is here:
for (i = 0; i < subscribers.length; i++) {
callSubscriber(subscribers[i].func, originalMessage, data);
}
subscribers array should be cloned before calling susbscribers.
It would be nice if I had an option that allows me to subscribe to a certain event and still get a notification, even if I subscribed to a message only after it already has been published.
Would like to know how can I use it with socket implementation.
I'm building a notification/messaging service (not-node.js based), and wanted a lightweight pubsub architecture that can connect to the socket and do the pub-sub calling.
Have you tried it?
It should be better not to use both tab and whitespaces for code indent.
One reason is tab will be explain to 8 character width in some environment (ex: github)
And cause the code looks very bad for reading.
Hi, what about adding an option to choose a different channel / topic delimiter, say "/" instead of the standard "."?
Could be done like this: PubSub.configure({delimiter: "/"});
Shouldn't be too hard, so if you like I can make a pull request.
When an exception occurs in a subscribe handler pubsubjs catches it and rethrows it after a timeout to ensure that the message has been passed to all subscribers:
https://github.com/mroderick/PubSubJS/blob/master/src/pubsub.js#L40-L52
This behavior of throwing the exception at a later point seems to kill the exception stack, making it a lot harder to debug exceptions, for example when you have your dev tools set to pause on uncaught exceptions.
Possible solutions:
Hi,
been using PubSubJS for three months now and been loving it.
But I'm now in a bit of trouble because my code depends on an undocumented feature. I noticed that PubSub.publish() returns false if there are no subscribers for a channel so I created a bit of logic like so....
if(!PubSub.publish(DO_SOMETHING, {paramA:1, paramB:2})){
// publish will return false if there are no subscribers (I hope)
PubSub.publish(DO_SOMETHING_ELSE, {paramA:1, paramB:2});
}
On initial page load, this works fine. When app tries to publish to DO_SOMETHING and there's no subscriber DO_SOMETHING_ELSE is called which loads loads a module with code, templates, etc. and creates a subscription for DO_SOMETHING. When that module is unloaded the subscription is canceled, but PubSub.publish(DO_SOMETHING, {}) still returns true. This means that DO_SOMETHING_ELSE is never called after that, even if there's no subscription to respond to DO_SOMETHING.
Reviewing the code, it appears that the false positive is due to messageHasSubscribers() checking for the existence of a topic but not for one or more delivery functions. Would adding that functionality cause any trouble for other users of the PubSubJS?
Thanks
I would suggest to add the following line to package.json to enable proper module loading:
"main" : "./src/pubsub.js",
see http://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders
Then loading would be as easy as
var PS = require('pubsub-js');
Ognian
Thanks for an excellent library. There's a minor typo in your readme:
...
Cancel specific >subscripiton<
...
Can't find it in Bower.
bower install PubSubJS
ENOTFOUND Package PubSubJS not found
As of Buster 0.7.4 assert
, refute
and expect
are no longer global. PubSubJS tests expect that and hence tests are broken when using BustetJS 0.7.4+
See BusterJS changelog for more details http://docs.busterjs.org/en/v0.7.x/changelog/
https://gist.github.com/qfox/f33a51dc7189d98efe23
Basically, this test:
PubSub.publish('foo', 'bar');
PubSub.subscribe('foo', function(name, value) {});
Currently the callback is not being fired. However, in this case they are both (which is fine).
PubSub.subscribe('foo', function(name, value) {});
PubSub.publish('foo', 'bar');
PubSub.subscribe('foo', function(name, value) {});
Due to the async nature of pubsub I expect it to evaluate target handlers at emitting time, not at call time.
This basically also means this:
var foo = PubSub.subscribe('foo', function(name, value) { throw 'No dont call me!'; });
PubSub.publish('foo', 'bar');
PubSub.unsubscribe(foo);
I expect the subscriber NOT to be called because it was removed before actually emitting the event.
There's a simple way to increase the throughput of asynchronous events when they spawn each other.
The idea is to only have the first call to publish() call setTimeout, which creates an event pump for all the events that the first event spawned. These subsequent events get added to a queue, which the event pump drains. When the event queue is empty, the pump exits (returns in javascript), and the next event spawns a new event pump.
I've coded it up:
jsperf (unpublished): http://jsperf.com/pubsubjs-vs-jquery-custom-events/17
code: https://gist.github.com/1715452
(I also cleaned up the code a bit, but didn't have access to all the tests, which is why I didn't do this as a pull request.)
I wanted to do PubSub.unsubscribe('topic')
but can't. Instead to unsubscribe an event I either have to maintain the returned ids or I have to maintain a reference to the handler function.
If the unique id returned by subscribe
were to just be var token = ++lastUid
, you could overload the unsubscribe
method by checking for a number to do the same as strings do right now. Then you could use the string case to drop all handlers for a certain topic.
The only impact I see right now is to users who rely on the subscribe
return value being a string. I'm not sure why anyone would though since for them it's just a token.
The fixes are trivial but I don't know whether you're open to such a change.
I'm every day confusing that first arg is message and second is data.
I propose set obj param something like code below
subscriber( {
message:message,
data: data
});
CDN provides pubsub.js but it is not the latest version.
//cdn.jsdelivr.net/pubsubjs/1.4.2/pubsub.js
In addition to that, if README has URL of CDN, it will be more excellent.
It would be extremely nice if there would be ready built versions for people who don't have things like rake installed, nor have no use for it. Normal & jQuery version.
Is it possible to have late subscribers? Where a subscriber gets notified even if he subscribes later then the message fires
Please have a look at this demo: http://jsbin.com/pequr/10/edit?html,console,output
Is the use-case valid or is this a bug / deficiency?
It would be nice to support sticky events concept: the idea is that some events will "stick" in PubSub and if any subscriber subscribes for such events after them was published, the subscribers will still receive them upon registration.
Consider for example this use case: there is a system-wise event, broadcasting when the user was logged in. There are many components, which are interested in receiving this event. But not all off them were already loaded at the moment when log in took place.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.