流星一次或“静态”发布,无需收集跟踪

Posted

技术标签:

【中文标题】流星一次或“静态”发布,无需收集跟踪【英文标题】:Meteor one time or "static" publish without collection tracking 【发布时间】:2013-09-20 04:32:59 【问题描述】:

假设一个 Meteor 应用程序需要将包含 10,000 个文档的相同集合发送到每个客户端。

在较高的级别上,我知道服务器会为每个客户端订阅做一些记录 - 即,它跟踪订阅的状态,以便它可以为客户端发送适当的更改。但是,如果每个客户端都有相同的大型数据集,其中每个文档都有很多字段,那么这将非常低效。

似乎在used to be a way to send a "static" publish down the wire 那里发布了初始查询并且再也没有更改过。这似乎是一种更有效的方法。

在当前版本的 Meteor (0.6.5.1) 中有正确的方法吗?

编辑:澄清一下,这个问题与客户端反应无关。这是为了减少服务器端跟踪客户端集合的开销。

相关问题:Is there a way to tell meteor a collection is static (will never change)?

更新:事实证明,在 Meteor 0.7 或更早版本中执行此操作会导致一些严重的性能问题。请参阅 https://***.com/a/21835534/586086 了解我们如何解决此问题。

【问题讨论】:

【参考方案1】:

http://docs.meteor.com/#find:

Statics.find(, reactive: false )

编辑以反映评论:

您是否有一些信息表明 reactive: false 参数只是客户端?你可能是对的,这是一个合理的,也许是可能的解释。我没有时间检查,但我认为这也可能是服务器端指令,说不要轮询 mongo 结果集。愿意学习...

你说

However, this is horribly inefficient if each client has the same large data set where each document has many fields.

现在我们可能正在讨论服务器代码的效率,以及它轮询 mongo 源以获取服务器外部发生的更新。请提出另一个问题,这远远超出了我的回答能力!我怀疑每个连接的客户端都会发生一次,更有可能是应用服务器信息和 mongo 服务器之间的同步。

您发出的客户端请求(包括排序)都应标记为非响应式。这与您是否可以向它们发出排序指令,或者它们是否可以通过其他反应性重新触发是分开的,但不需要包括访问服务器。一旦每个文档到达客户端,它就会被缓存。你仍然可以做任何 minimongo 所做的事情,而不会损失能力。没有客户端询问服务器是否有更新,您无需将其关闭。服务器仅在需要时推送。

【讨论】:

这是一个客户端功能。我说的是服务器端的订阅跟踪。例如,如果集合按Session 变量排序,则可能仍希望在客户端使用反应式游标。 顺便说一句,我认为您在问题中添加了条件,然后有人否决了我的两个正确答案。面对其他人判断这些答案很有帮助。可能不符合这种(免费)合作的精神。 我对你的答案投了反对票,因为我认为你误解了这个问题,而且你的答案具有误导性。有关find 的反应性的详细信息,请参阅docs.meteor.com/#find。您不希望客户端通过静态订阅进行反应,这根本不是真的。同样,一个具体的例子是,如果您要更改客户端的排序顺序。如果您的游标是非反应性的,那么在您更新排序参数时它们不会改变。问题不在于服务器不会在不需要时推送数据;这是服务器不必要地跟踪客户端数据。 如果您以不同的排序顺序重新启动助手,无论是否响应,您的模板都会发生变化。好吧,对不起,这是一场令人讨厌的比赛。 1)反应性!=以不同的顺序检索。 2)我们同意查找的参考。您只看到“客户”一词(实际上并不存在),因为您以自己的方式解释“反应式”一词。我将其解释为“监视更改并重新发布它们”。如果 mongo db 从另一个应用程序获取插入,则在这种情况下非响应式可能意味着不要继续重新轮询 db 服务器。我们不需要互相说服。 不,你是对的。我正在考虑一个取决于反应会话变量的排序说明符。在任何情况下,reactive: false 仅是客户端(根据文档),您不能使用它来保存服务器上的工作。我不明白没有时间检查的评论;正如我链接的那样,它显然在文档中。您所说的避免观察/轮询的内容与您的建议不同。【参考方案2】:

此外,您可以将数据脚本化到 js 文件中,作为数组或对象,将其最小化,然后将其作为不同的资源链接。看 http://developer.yahoo.com/performance/rules.html 用于添加过期或缓存控制标头。您可能不想让流星为您捆绑它。

这将是最少的流量,并且可以使您网站的后续加载更快。

【讨论】:

这难道不会完全忽略在客户端集合中提供数据的意义吗?【参考方案3】:

我认为使用手动发布 (this.added) 仍然可以消除服务器观察数据以进行更改而产生的开销。观察者要么需要手动添加,要么通过返回 Collection.curser 创建。

如果数据集很大,您可能还会担心 merge box 为每个客户端保存数据副本的开销。要摆脱这种情况,您可以在本地复制集合并停止订阅。

var staticData = new Meteor.Collection( "staticData" );

if (Meteor.isServer )
  var dataToPublish = staticData.find().fetch();  // query mongo when server starts

  Meteor.publish( "publishOnce" , function () 
    var self = this;
    dataToPublish.forEach(function (doc) 
      self.added("staticData", doc._id, doc);  //sends data to client and will not continue to observe collection
    );
  );


if ( Meteor.isClient )
  var subHandle = Meteor.subscribe( "publishOnce" );  // fills client 'staticData' collection but also leave merge box copy of data on server

  var staticDataLocal = new Meteor.Collection( null );  // to store data after subscription stops

  Deps.autorun( function()
    if ( subHandle.ready() )
      staticData.find(  ).forEach( function ( doc ) 
        staticDataLocal.insert( doc );  // move all data to local copy
      );
      subHandle.stop();  // removes 'publishOnce' data from merge box on server but leaves 'staticData' collection empty on client
    
  );

更新:我在代码中添加了 cmets 以使我的方法更清晰。订阅句柄上stop() 的流星文档说“这通常会导致服务器指示客户端从客户端缓存中删除订阅的数据”所以也许有一种方法可以停止订阅(从合并框中删除)将数据留在客户端。这将是理想的,并且可以避免客户端的复制开销。

无论如何,setflush 的原始方法也会将数据留在合并框中,所以也许没关系。

【讨论】:

我知道你打算用这个去哪里,但订阅句柄与集合游标不同。无论如何,所有这些东西都将被插入到客户端集合中,因此到另一个集合的额外副本只是浪费计算。应该有一种更简洁的方法来通过订阅同步的集合来实现这一点。 我同意订阅句柄与集合游标不同。我只使用订阅句柄来停止订阅 - 否则所有数据将保留在服务器的客户端数据副本(合并框)中。在不丢失订阅数据的情况下停止订阅是理想的,但如果没有,则副本是必要的。 是的,这里有两个优化:1) 不会产生 mongo 观察的开销和 2) 不会产生合并框/客户端缓​​存/服务器上的任何东西的存储损失。您的回答为 1) 提供了最佳解决方案,但 2) 目前仍悬而未决。【参考方案4】:

作为对 Meteor 调用的响应,返回一个文档数组(使用 fetch()) 无反应或日志记录。在客户端,当您进行查询时创建一个 dep,或从会话中检索密钥,它在客户端上是响应式的。

Mini mongo 只是在你和你的数据之间使用解释 dsl 的语法进行 js 数组/对象操作。

【讨论】:

【参考方案5】:

新的fast-render package 使一次性发布到客户端集合成为可能。

var staticData = new Meteor.Collection ('staticData');

if ( Meteor.isServer )

  FastRender.onAllRoutes( function()
    this.find( staticData,  );
  );

【讨论】:

【参考方案6】:

正如您已经在 googlegroups 中指出的那样,您应该使用 Meteor 方法将静态数据发送到客户端。 还有 this neat package 用于使用方法而不会出现异步问题。

【讨论】:

以上是关于流星一次或“静态”发布,无需收集跟踪的主要内容,如果未能解决你的问题,请参考以下文章

Django收集静态错误

课堂笔记0518 static final

无需 DLL 静态链接 zlib

statics

django收集静态寻找不存在的目录

由于静态文件收集原因,Heroku 拒绝推送