What is the best way to unsubscribe a callback during publish?

457 views
Skip to first unread message

Paul

unread,
Aug 27, 2011, 8:17:16 AM8/27/11
to Amplify
Hi,

If I try and unsubscribe my callback during the callback itself I get
the following error (in Firefox 6 - but I think browser is
irrelevant):

subscription is undefined
[Break On This Error] ret =
subscription.callback.apply( subscription.context, args );

amplify.js (line 38)

which is the 3rd line in this snippet:

[CODE]
for ( length = subscriptions[ topic ].length; i < length; i++ ) {
subscription = subscriptions[ topic ][ i ];
>>>> ret = subscription.callback.apply( subscription.context, args );
if ( ret === false ) {
break;
}
}
[/CODE]

I think this is happening because my call to unsubscribe is removing a
callback from subscriptions[ topic ], but the loop does not expect
this. Sample code as follows:

[SAMPLE CODE]
function oneTimeOnlyCallback(data) {
amplify.unsubscribe(topic, oneTimeOnlyCallback);
doSomething(data);
}

amplify.subscribe(topic, oneTimeOnlyCallback);
[/SAMPLE CODE]


My question is, is there any way to have a callback unsubscribe itself
from a topic during it receiving the notification from publish?
*Without* it breaking this loop.

I want to do this as I only want to be notified of a particular topic
once, and don't want the subscription for the topic left registered
after this.

Cheers.

Paul.

Jonathan Sharp

unread,
Aug 29, 2011, 8:57:19 AM8/29/11
to ampl...@googlegroups.com
Yep! File a bug and we'll get it fixed!

Paul

unread,
Sep 1, 2011, 5:27:56 PM9/1/11
to Amplify
Sure, will do. Thanks for the reply.

My own patch was to just null the subscription in the subscriptions
array, have publish() watch out for nulls, and then do some form of
null tidy-up in the subscriptions after all the publish() callbacks
had been fired.

On Aug 29, 1:57 pm, Jonathan Sharp <jonat...@appendto.com> wrote:
> Yep! File a bug and we'll get it fixed!
>

Jonathan Sharp

unread,
Sep 1, 2011, 5:28:48 PM9/1/11
to ampl...@googlegroups.com
Yep, sounds good, could you send a pull request?

Cheers,
- Jonathan

Paul

unread,
Sep 27, 2011, 6:06:36 PM9/27/11
to Amplify
Sorry, only just checked this group again!

I've not yet got to grips with Git I'm afraid (I *will* get around to
it), so I just posted the patch as a comment to the issue I raised.

Evan Davis

unread,
Feb 27, 2012, 12:02:07 PM2/27/12
to ampl...@googlegroups.com
Bump! It'd be great to have a way to unsubscribe anonymous functions as well; something like amplify.subscribeOnce(topic, callback) would be killer.

Eric Strathmeyer

unread,
Feb 27, 2012, 12:15:07 PM2/27/12
to ampl...@googlegroups.com
Hi Evan,

To get that effect, you can wrap your function in _.once()

Jim Cowart

unread,
Feb 28, 2012, 1:13:20 AM2/28/12
to Amplify
Evan & Eric - using underscore's "once" method would work, however, it
won't actually remove the subscription from amplify. I've put
together a quick and dirty example of implementing your own "once"
wrapper around amplify's subscribe call:

var slice = [].slice,
once = function( topic, context, callback, priority ) {
if ( arguments.length === 3 && typeof callback === "number" )
{
callback = context;
}
else if ( arguments.length === 2 ) {
callback = context;
}
var fn = function() {
callback.apply(this, slice.call(arguments,0));
amplify.unsubscribe(topic, fn);
}

return amplify.subscribe( topic, context, fn, priority );
};


You can see a working fiddle example of the code here:
http://jsfiddle.net/ifandelse/XUWEr/

Hope that helps!

On Feb 27, 12:15 pm, Eric Strathmeyer <estrathme...@gmail.com> wrote:
> Hi Evan,
>
> To get that effect, you can wrap your function in _.once()http://documentcloud.github.com/underscore/#once
>
>
>
>
>
>
>
> On Monday, February 27, 2012 12:02:07 PM UTC-5, Evan Davis wrote:
>
> > Bump! It'd be great to have a way to unsubscribe anonymous functions as
> > well; something like *amplify.subscribeOnce(topic, callback)* would be

Eric Strathmeyer

unread,
Feb 28, 2012, 1:33:25 AM2/28/12
to ampl...@googlegroups.com
Hi Jim,

You're right that _.once does not remove the subscription, but I think it would be okay to use in rare situations. If this is a performance issue for you, it means that you're subscribing many one-time-use functions into a global pubsub namespace. I would not recommend that pattern. Instead, if I were dealing with a lot of one-time-use functions, I'd probably go with jQuery deferreds, or maybe an array full of $.Callback('once')s.

Your implementation is perfect, but I'm not personally sure it needs to be included in the library. The maintainers may feel differently.

Cheers,
-Eric

Douglas Neiner

unread,
Feb 28, 2012, 1:40:47 AM2/28/12
to Evan Davis, ampl...@googlegroups.com
Evan,

If you are only doing this once or twice, you can also just use a named callback function:

amplify.subscribe( "topic.name", function once () {
   amplify.unsubscribe( "topic.name", once );

   // your code here.
});

If you do this a lot, Jim's solution is more elegant and is closer to what I use in actual projects.

Doug


appendTo()

Doug Neiner // Senior Designer
1-877-578-3794 x 1007
@dougneiner


1-877-JQUERY-HELP
1-303-747-6007
http://appendTo.com

Jim Cowart

unread,
Feb 29, 2012, 12:03:31 AM2/29/12
to Amplify
Eric,
I doubt we will be adding that functionality to amplify core, so
my example wasn't intended to convey that in any way. I just wanted
to address the question of how to unsubscribe from within a callback.
I agree, there are many options for single-time-init, but I would
avoid leaving subscriptions in place that are no longer needed, since
the internals of amplify core will still attempt to invoke it (wrapped
in _.once or not). I personally find that to be less surface area for
the encroachment of bugs over time - and a good habit to have in
dealing with any pub-sub provider.

-Jim

Jim Cowart /* Senior Architect */
a.k.a. @ifandelse
1-877-578-3794 x 1008
http://appendTo.com
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages