Метеор: Tracker.autorun и dep.change вызывают бесконечный цикл

Я использую новый Tracker.Dependency для отслеживания нескольких вещей, но он вызывает бесконечный запуск автозапуска в приведенном ниже коде. Что случилось? Приведенный ниже код является нормальным, когда я разделяю getSong и getSongId, чтобы они зависели от dep и dep2, а не только от dep.

SongManager = {
  dep: new Tracker.Dependency,
  dep2: new Tracker.Dependency,
  init: function(songId) {
    var self = this;
    this.setSongId(songId);
    Meteor.subscribe('song', songId);
    Tracker.autorun(function(){
      var songs = self.getSongCursor().fetch();
      if (songs.length > 0) {
        self.song = songs[0];
        self.dep.changed();
      }
    })
  },
  getSongCursor: function(){
    return Songs.find({_id: this.getSongId()});
  },
  getSong: function(){
    this.dep.depend();
    return this.song;
  },
  getSongId: function(){
    this.dep2.depend();
    return this.songId;
  },
  setSongId: function(arg){
    this.songId = arg;
    this.dep2.changed();
  },
};

1 ответ

Решение

Проблема в том, что вы создаете круговую зависимость. Я бы порекомендовал использовать ReactiveVar для этого, а не для работы с API зависимостей более низкого уровня.

meteor add reactive-var

Тогда вы можете просто сделать это:

SongManager = {

  song: new ReactiveVar(),

  songId: new ReactiveVar(),

  init: function(songId) {
    this.songId.set(songId);
    this.computation = Tracker.autorun(_.bind(this.update, this));
  },

  update: function() {
    var songId = this.songId.get();
    Meteor.subscribe('song', songId);
    this.song.set(Songs.findOne(songId));
  },

  stop: function() {
    this.computation.stop();
  }
};

SongManager.init(oldSongId);
SongManager.songId.set(newSongId);

// After enough time has passed for the subscription to update and tracker to flush:
var currentSong = SongManager.song.get();
console.log(currentSong._id === newSongId); // true

Я также добавил способ остановить вычисления автозапуска, чтобы они не работали в фоновом режиме, когда они больше не нужны. Обратите внимание, что поскольку подписка выполняется в рамках автозапуска, она будет автоматически остановлена ​​и перезапущена, когда songId изменения. Функция обновления будет запущена дважды, но Meteor знает, что не нужно отправлять два одинаковых запроса на подписку.

Другие вопросы по тегам