是否有必要停止订阅 Meteor 的辅助级别订阅?
Is it necessary to stop subscribing in helper level subscriptions with Meteor?
根据the docs:
If you call Meteor.subscribe within a reactive computation, for example using Tracker.autorun, the subscription will automatically be cancelled when the computation is invalidated or stopped;
然后明确提到不需要在 autorun
内停止订阅。
流星帮手也是这样吗?我相信他们算作 reactive computation
,但我不完全确定!
编辑
这是代表这种情况的代码片段。
那么问题来了:我需要做些什么来停止 objectsSub
还是全部自动排序?
<template name ="Foo">
{{#with myContext}}
{{#each objects}}
<!--Show stuff-->
{{/each}}
{{/with}}
</template>
Template.Foo.onCreated(function(){
this.subscribe('myContextSub');
});
Template.foo.helpers({
myContext(){
return MyContextCollection.findOne();
},
objects(){
Meteor.Subscribe('objectsSub',this.someContextAttribute);
return ObjectsCollection.find({});
},
});
我不喜欢在助手中做任何有副作用的事情,比如去服务器。当模板处于活动状态时,可以多次调用助手,所以恕我直言,它实际上应该只做 return 个值。
在您的情况下,我至少会将订阅绑定到模板,这样当模板被销毁时订阅就会消失。例如
Template.foo.helpers({
objects() {
Template.instance().subscribe('objectsSub',this.someContextAttribute);
return ObjectsCollection.find({});
},
});
更有可能的是,当发布主集合 (myContextSub) 时,我会在服务器端处理这个 "join"。但这只是在从属集合 (objectsSub) 预计不会反应的情况下。 (在发布中,您可以在添加和更改的事件上设置侦听器,并向发布的对象添加额外的字段,即来自 objectsSub 的数据)。
如果 objectsSub 是反应式的,那么我可能会在模板的 onCreated() 中处理订阅。在客户端,您可以在主集合上设置一个添加的侦听器,然后在主集合中的项目发布时订阅相关的从属集合。助手然后可以像现在一样简单地执行 find() 。例如
Template.foo.onCreated(function() {
let self = this;
self.subscribe('myContextSub');
let cursor = MyContextCollection.find();
cursor.observe({
added: function(newDocument) {
// loop through the objects on newDocument, pulling out the context attributes to subscribe one or more times...
self.subscribe('objectsSub', someContextAttribute[s]);
},
changed: function(newDocument, oldDocument) {
// same as added
}
});
});
现在slave helper可以更简单了:
Template.Foo.helpers({
myContext() {
return MyContextCollection.findOne();
},
objects() {
return ObjectsCollection.find({});
},
});
在第二个示例中,也许有点奇怪的是我使用的是 find() 而不是您正在使用的 findOne(),以便以这种方式访问侦听器。所以也许您需要检查它在客户端上的发布或过滤方式。
如果您想坚持使用 findOne(),同样的概念适用:一旦数据被 returned,您可以检查它并订阅您需要的从属集合。
问得好!
你说得对,模板助手实际上是一种反应式计算。因此,根据文档,您不必停止由助手启动的订阅。但是你知道当你假设时会发生什么......
所以我决定对此进行测试,以确保它在实践中确实如此。根据我的测试,您的问题的答案是 您不必停止由助手 启动的订阅。
如果您好奇,这是我的测试代码(请注意,我在我的应用程序中使用了 collection,其中包含活跃用户列表)。
<template name='main_template'>
<p>Number of Active Users: {{numUsers}}</p>
{{#if isNotDestroyed}}
<p>Number of Active Users (from sub-template): {{> sub_template}}</p>
{{/if}}
<a href="#" class="js-destroy">Destroy sub-template</a>
</template>
<template name='sub_template'>
{{numUsers}}
</template>
Template.main_template.onCreated(function() {
this.destory = new ReactiveVar(false);
});
Template.main_template.helpers({
numUsers: function() {
return ActiveUsers.find().count();
},
isNotDestroyed: function() {
return !Template.instance().destory.get();
}
});
Template.main_template.events({
'click .js-destroy'(template, instance) {
console.log('setting destory');
instance.destory.set(true);
},
});
Template.sub_template.onCreated(function() {
console.log("I was created!");
});
Template.sub_template.onDestroyed(function() {
console.log("I was destroyed!");
});
Template.sub_template.helpers({
numUsers: function() {
Meteor.subscribe('activeUsers');
return ActiveUsers.find().count();
},
});
如您所见,我在子模板中订阅了collection,但我在统计主模板和子模板中的记录数。在初始 运行 上,两者都计算 return 相同的值。但是,当我 "destroyed" 子模板(通过使用 ReactiveVar 实现)时,主模板中的计数变为 0。这意味着订阅已停止并且本地 collection 已被清除。
最后一点,我完全同意@zim 的建议。除了他的建议,您还可以使用 Meteor Publish Composite 包来处理这个问题,只需 1 个订阅。
您可以使用这个 chrome extension to see when meteor is subscribing and unsubscribing. You will probably see it unsubscribing from your subscription in the helper as @jordanwillis pointed out. Also I recommend this server transform package 在一个订阅中完成所有事情,而不是在一个助手中。
根据the docs:
If you call Meteor.subscribe within a reactive computation, for example using Tracker.autorun, the subscription will automatically be cancelled when the computation is invalidated or stopped;
然后明确提到不需要在 autorun
内停止订阅。
流星帮手也是这样吗?我相信他们算作 reactive computation
,但我不完全确定!
编辑
这是代表这种情况的代码片段。
那么问题来了:我需要做些什么来停止 objectsSub
还是全部自动排序?
<template name ="Foo">
{{#with myContext}}
{{#each objects}}
<!--Show stuff-->
{{/each}}
{{/with}}
</template>
Template.Foo.onCreated(function(){
this.subscribe('myContextSub');
});
Template.foo.helpers({
myContext(){
return MyContextCollection.findOne();
},
objects(){
Meteor.Subscribe('objectsSub',this.someContextAttribute);
return ObjectsCollection.find({});
},
});
我不喜欢在助手中做任何有副作用的事情,比如去服务器。当模板处于活动状态时,可以多次调用助手,所以恕我直言,它实际上应该只做 return 个值。
在您的情况下,我至少会将订阅绑定到模板,这样当模板被销毁时订阅就会消失。例如
Template.foo.helpers({
objects() {
Template.instance().subscribe('objectsSub',this.someContextAttribute);
return ObjectsCollection.find({});
},
});
更有可能的是,当发布主集合 (myContextSub) 时,我会在服务器端处理这个 "join"。但这只是在从属集合 (objectsSub) 预计不会反应的情况下。 (在发布中,您可以在添加和更改的事件上设置侦听器,并向发布的对象添加额外的字段,即来自 objectsSub 的数据)。
如果 objectsSub 是反应式的,那么我可能会在模板的 onCreated() 中处理订阅。在客户端,您可以在主集合上设置一个添加的侦听器,然后在主集合中的项目发布时订阅相关的从属集合。助手然后可以像现在一样简单地执行 find() 。例如
Template.foo.onCreated(function() {
let self = this;
self.subscribe('myContextSub');
let cursor = MyContextCollection.find();
cursor.observe({
added: function(newDocument) {
// loop through the objects on newDocument, pulling out the context attributes to subscribe one or more times...
self.subscribe('objectsSub', someContextAttribute[s]);
},
changed: function(newDocument, oldDocument) {
// same as added
}
});
});
现在slave helper可以更简单了:
Template.Foo.helpers({
myContext() {
return MyContextCollection.findOne();
},
objects() {
return ObjectsCollection.find({});
},
});
在第二个示例中,也许有点奇怪的是我使用的是 find() 而不是您正在使用的 findOne(),以便以这种方式访问侦听器。所以也许您需要检查它在客户端上的发布或过滤方式。
如果您想坚持使用 findOne(),同样的概念适用:一旦数据被 returned,您可以检查它并订阅您需要的从属集合。
问得好!
你说得对,模板助手实际上是一种反应式计算。因此,根据文档,您不必停止由助手启动的订阅。但是你知道当你假设时会发生什么......
所以我决定对此进行测试,以确保它在实践中确实如此。根据我的测试,您的问题的答案是 您不必停止由助手 启动的订阅。
如果您好奇,这是我的测试代码(请注意,我在我的应用程序中使用了 collection,其中包含活跃用户列表)。
<template name='main_template'>
<p>Number of Active Users: {{numUsers}}</p>
{{#if isNotDestroyed}}
<p>Number of Active Users (from sub-template): {{> sub_template}}</p>
{{/if}}
<a href="#" class="js-destroy">Destroy sub-template</a>
</template>
<template name='sub_template'>
{{numUsers}}
</template>
Template.main_template.onCreated(function() {
this.destory = new ReactiveVar(false);
});
Template.main_template.helpers({
numUsers: function() {
return ActiveUsers.find().count();
},
isNotDestroyed: function() {
return !Template.instance().destory.get();
}
});
Template.main_template.events({
'click .js-destroy'(template, instance) {
console.log('setting destory');
instance.destory.set(true);
},
});
Template.sub_template.onCreated(function() {
console.log("I was created!");
});
Template.sub_template.onDestroyed(function() {
console.log("I was destroyed!");
});
Template.sub_template.helpers({
numUsers: function() {
Meteor.subscribe('activeUsers');
return ActiveUsers.find().count();
},
});
如您所见,我在子模板中订阅了collection,但我在统计主模板和子模板中的记录数。在初始 运行 上,两者都计算 return 相同的值。但是,当我 "destroyed" 子模板(通过使用 ReactiveVar 实现)时,主模板中的计数变为 0。这意味着订阅已停止并且本地 collection 已被清除。
最后一点,我完全同意@zim 的建议。除了他的建议,您还可以使用 Meteor Publish Composite 包来处理这个问题,只需 1 个订阅。
您可以使用这个 chrome extension to see when meteor is subscribing and unsubscribing. You will probably see it unsubscribing from your subscription in the helper as @jordanwillis pointed out. Also I recommend this server transform package 在一个订阅中完成所有事情,而不是在一个助手中。