【问题标题】:Is it possible (with Meteor) to control when publications are pushed to subscribed clients?是否可以(使用 Meteor)控制何时将发布推送给订阅的客户端?
【发布时间】:2015-12-25 19:40:35
【问题描述】:

使用 Meteor 编程时,是否可以控制何时将发布(DDP 更新到本地 MiniMongo)推送到订阅的客户端。看起来默认行为是在对关联集合进行任何更改后立即推送更改。在我的应用程序中,这将非常低效并导致许多不必要的更新。

理想情况下,我想做的是延迟推送更改,直到我在另一个集合中有特定更改。

因此,例如,如果我有以下集合以及相关的出版物和订阅:

// Client and server
Scores = new Meteor.Collection('scores');
GameState = new Meteor.Collection('gameState');

Meteor.publish('scores', function(gameId) {
    return Scores.find({id: gameId});
});

Meteor.publish('gameState', function(gameId) {
    return GameState.find({id: gameId});
});

// Client only
Meteor.subscribe('scores');
Meteor.subscribe('gameState');

我想做的是延迟更新客户端的本地“分数”集合,直到游戏状态达到特定状态。

【问题讨论】:

  • 这不是一个完整的答案,但请查看observeChanges()docs.meteor.com/#observe_changes - 在服务器端使用它来填充集合并仅在发生所需更改时交付。这是一个灵活但复杂的框架。另见eventedmind.com/tracks/feed-archive/…
  • 我确实想知道是否可以使用 observeChanges() 和另一个订阅来解决问题。如果在订阅中传递了标志,我能够避免在现有出版物上推送更新,那会更容易(如果不一定是“最佳”方式)。

标签: javascript meteor


【解决方案1】:

如果我对问题的理解正确,您可以结合使用autorun 和会话变量来触发订阅。像这样的:

Tracker.autorun(function() {
  var gameId = Session.get('currentGame');
  if (gameId && Session.get('excitingLevel')) {
    Meteor.subscribe('scores', gameId);
    Meteor.subscribe('gameState', gameId);
  }
});

这里我使用excitingLevelcurrentGame(难道没有游戏正在进行吗?)来激活订阅。另请注意,autorun 足够聪明,可以在不再满足条件时停止订阅。所以如果玩家离开游戏(Session.set('currentGame', undefined))或者关卡不再精彩,订阅就会结束。

其他说明

  • 如果游戏状态变化非常快,我可能值得评估streams,而不是使用集合作为游戏状态。
  • 可能需要执行某种load testing 来确定最佳解决方案。

【讨论】:

  • 因此,与其试图避免总是从服务器推送更改,不如建议客户端只在他们有兴趣接收更新时订阅并在他们没有兴趣时停止订阅?
  • 是的,完全正确。假设您可以确定客户端的必要条件,这可能是最容易实施的解决方案。就服务器性能而言,它几乎肯定是最好的解决方案。我建议仅在必须在服务器上确定必要条件时才在服务器上使用观察器(如@nalply 建议的那样)。否则很难证明观察的性能损失是合理的。有关更多信息,请参阅我对this 问题的回答。
  • 感谢您花时间解释。我唯一关心的仍然是性能:启动和停止订阅的成本是多少?如果我采用这种解决方案,我会让客户定期开始和停止订阅。
  • 定期启动和停止订阅对于流星应用来说是完全正常的行为,与此相关的固有费用很低。但是,您仍然必须将数据传输到客户端,因此如果您的订阅有大量文档,并且每秒启动和停止多次,这可能不是最佳解决方案。我在上面的回答中添加了一些额外的注释。
【解决方案2】:

在服务器端代码中发布scores 或多或少像这样:

GameState = new Meteor.Collection('gameState')

/* Publish a custom Scores collection */
Meteor.publish("scores", function () {
  var self = this

  gameStateCursor = GameState.find();
  observerHandle = gameStateCursor.observe({
    added: function (document, index) {
      /* This is called whenever a new document is added to the game state. */

      if (/* gameState ready to publish to scores */)
        self.changed("scores", scoreId, scoreData)

      /* or use self.added() */
    },
    /* more functions as described in publish() */

  }
}

这不是一个完整的答案,而是一个粗略的大纲。这个observe() 框架非常强大,但是低级。几乎一切皆有可能。我可以想象用observe() 发布波浪数据的傅里叶变换,这太强大了。

请仔细阅读https://docs.meteor.com/#meteor_publishhttps://docs.meteor.com/#publish_added及以下(添加、更改和删除)。

【讨论】:

  • 感谢您抽出宝贵时间提供答案。那么,在这个例子中,我们(服务器)可以控制多久将更新推送给“scores”发布的订阅者?只有当我们调用 self.changed()/updated() 等时才会推送更改?
  • 正确!您在docs.meteor.com/#meteor_publish 的按房间计数发布示例中看到(向下滚动查看更大的代码示例),他们发布了一个派生集合,即按房间计数。
猜你喜欢
  • 1970-01-01
  • 2011-08-04
  • 2019-11-02
  • 1970-01-01
  • 2022-12-19
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多