Reputation: 100010
According to this article here:
https://dweldon.silvrback.com/common-mistakes
Subscriptions don't block
Many aspects of the framework seem like magic. So much so that it may cause you to forget how web browsers work. Take this simple example:
Meteor.subscribe('posts');
var post = Posts.findOne();
The idea that post will be undefined is the root cause of roughly one in twenty meteor questions on stackoverflow.
So then why doesn't subscribe have a callback, and if it does, why isn't it referenced more often by the Meteor literati?
Why don't we have:
Meteor.subscribe('posts', function(err, posts){
//when the items/posts actually arrive
});
I hope my question makes sense.
Upvotes: 25
Views: 20468
Reputation: 4366
Meteor.subscribe
has been enhanced since v1.2. One of its callbacks onError
is now replaced with onStop
in Meteor v1.2.0.2 documentation
callbacks Function or Object
Optional. May include onStop and onReady callbacks. If there is an error, it is passed as an argument to onStop. If a function is passed instead of an object, it is interpreted as an onReady callback.
Having that enhancement, Meteor.subscribe
is used with callbacks as an object
Meteor.subscribe( 'collection', {
onStop: function( error /* optional */ ) {
// when the sub terminates for any reason,
// with an error argument if an error triggered the stop
},
onReady: function() {
// when ready
}
});
However, onError
still works for backward compatibility. Be aware that some popular packages, such as SubsManager still uses onError
. That being said such snippet below is now deprecated but doesn't break .
Meteor.subscribe( 'collection', {
onError: function( error ) {
// if the subscribe terminates with an error
},
onReady: function() {
// when ready
}
});
On the other hand, Meteor.subscribe
can be used with a callback as a function as before
Meteor.subscribe( 'collection', function() {
// when ready
});
As my personal notice, if Meteor.subscribe
happens to be passed with careless multiple callback functions, only the last one takes effect as the onReady
callback.
Meteor.subscribe( 'collection', function() {
// this doesn't execute.
}, function() {
// when ready.
});
The associated Git commitment is listed here for a reference.
Upvotes: 12
Reputation: 11376
Maybe I don't get the question, but the Meteor.Subscribe function has callbacks named onError and onReady methods.
Optional. May include onError and onReady callbacks. If a function is passed instead of an object, it is interpreted as an onReady callback.
For example.
Meteor.subscribe("posts", {
onReady: function () { console.log("onReady And the Items actually Arrive", arguments); },
onError: function () { console.log("onError", arguments); }
});
Also check this GitHub issue
Upvotes: 51
Reputation: 64312
Note: I have updated the article after reading this question.
While subscribe does have an optional callback, I intentionally avoided it in the original article because there aren't currently any common patterns that use it. In other words, I didn't want readers to come away from the article thinking that callbacks were actually the right solution to this problem.
In production applications, subscriptions typically come in two flavors:
Global: initiated as soon as the client starts, or maybe in an autorun.
Route: initiated as via a subscriptions
or waitOn
option.
It's also worth noting that in recent weeks, the template subscription pattern has emerged, though it hasn't seen wide adoption yet.
In all of these cases, the subscription is started and then can either be asynchronously checked for a reactive ready
state, or ignored with the use of guards to prevent reference errors.
Because ready
is reactive, this effectively gives us the same benefits of a callback, but with fewer lines of code. Let's look at two examples:
Meteor.subscribe('posts', function() {
Session.set('postsReady', true);
});
Tracker.autorun(function() {
if (Session.get('postsReady'))
showFancyAnimation();
});
var handle = Meteor.subscribe('posts');
Tracker.autorun(function() {
if (handle.ready())
showFancyAnimation();
});
Both examples demonstrate the same concept - subscribing and then reactively testing the state of the subscription. As you can see there really isn't a benefit to the callback.
Finally, (as I now point out in the article), subscriptions are often spatially separated from the code which uses them. You'll typically subscribe in your route code and consume the results in your templates. For this reason you almost never see code which looks like:
Meteor.subscribe('posts', function() {
showFancyAnimation();
});
In fact, the only place I ever encounter code like the above is in SO answers because the author is trying to make a quick demonstration rather than trying to show a typical usage pattern.
Upvotes: 20