是否有必要停止订阅 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 在一个订阅中完成所有事情,而不是在一个助手中。