Помощник Meteor вызывается несколько раз одной переменной шаблона

Tweets = new Meteor.Collection('tweets');

if (Meteor.isClient) {

  Meteor.subscribe('tweets');

  Template.Panel.helpers({
    items: function() {
      var days_tweets = Tweets.find();
      console.log(days_tweets.count());
      return days_tweets;
    });
  }

if (Meteor.isServer) {
  Meteor.publish('tweets', function() {
    return Tweets.find({}, {limit: 1000});
  });

Шаблон:

<body>
<h1>This is a list of tweets</h1>
  {{> Panel}}
</body>

<template name="Panel">
<h2>A list of tweets sorted by size</h2>
    {{#each items}}
        <p>item</p>
    {{/each}}
</template>

И вывод консоли при загрузке страницы:

Tweet count:  0
Tweet count:  129
Tweet count:  272
Tweet count:  366
Tweet count:  457
Tweet count:  547
Tweet count:  672
Tweet count:  814
Tweet count:  941
Tweet count:  1000

Таким образом, вспомогательная функция срабатывает 10 раз при загрузке страницы (количество раз варьируется). Кто-нибудь может объяснить, что здесь происходит? Я не могу найти никаких ссылок на это, примите в ситуациях, когда помощник вызывается из нескольких {{}} в шаблоне. Также любой способ остановить это? В конце концов мне нужно обработать твиты за один раз, прежде чем они будут отображены.


person kendlete    schedule 13.11.2014    source источник


Ответы (1)


Когда вы выполняете поиск, метеор регистрирует зависимость для этого помощника шаблона от коллекции, в которой вы выполнили поиск. Из-за этой зависимости метеор будет вызывать помощник шаблона для каждой модификации коллекции.

Если вы еще не подписались, в клиентскую копию вашей коллекции монго не загружаются данные. Только когда вы вызовете подписку, метеор начнет получать данные с сервера.

Таким образом, метод вызывается несколько раз, потому что подписка продолжает вставлять новые документы в вашу локальную копию коллекции монго, вызывая новые вызовы помощника шаблона.

Лучший способ противостоять любым проблемам, которые это может вызвать, — подписаться в помощнике и использовать метод ready в подписке документация. Ready также является реактивным, поэтому, когда все данные будут загружены, ready будет изменен на true, и помощник будет вызван снова.

  Template.Panel.helpers({
      items: function() {
          var ready = Meteor.subscribe('tweets').ready();
          var days_tweets = Tweets.find();

          return {
              data: days_tweets,
              ready: ready
          };
      });
  }

Сам шаблон:

{{#with items}}
     {{#if ready}}
         {{#each data}}
             <p>item</p>
         {{/each}}
     {{else}}
         Show a spinner or whatever
     {{/if}}
{{/with}}
person Marco de Jongh    schedule 13.11.2014
comment
Хорошо спасибо. Я предполагал нечто подобное. Есть ли способ остановить это? (при условии, что коллекция на сервере не меняется, как здесь). Кажется странным, что синхронизация между фиксированным сервером и коллекцией клиентов работает как бы асинхронно. - person kendlete; 14.11.2014
comment
@kendlete обновил мой ответ примером того, как работать с поведением системы подписки метеора. - person Marco de Jongh; 14.11.2014
comment
Meteor.subscribe() также имеет обратный вызов onready в документации, который можно использовать для задержки вставки дополнительного кода до тех пор, пока подписка не будет готова. Это отличается от .ready(), который возвращает логическое значение, если подписка готова. Возможно, немного более громоздкий, чем подход Марко. - person Paul; 14.11.2014
comment
Спасибо, очень полезно. Я также поставлю if (ready) в помощник, чтобы избежать обработки твитов до синхронизации подписки (они будут сгруппированы перед рендерингом). - person kendlete; 14.11.2014