4

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

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

似乎曾经有一种方法可以在线发送“静态”发布,其中发布了初始查询并且再也不会更改。这似乎是一种更有效的方法。

在当前版本的 Meteor (0.6.5.1) 中是否有正确的方法来执行此操作?

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

一个相关的问题:有没有办法告诉流星集合是静态的(永远不会改变)?

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

4

6 回答 6

1

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

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

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
    }
  });
}

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

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

于 2013-09-16T09:37:28.863 回答
1

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

Statics.find({}, {reactive: false} )

编辑以反映评论:

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

你说

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

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

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

于 2013-09-16T06:05:13.350 回答
1

正如您已经在 googlegroups 中指出的那样,您应该使用 Meteor 方法将静态数据发送到客户端。
并且有一个简洁的包用于处理方法而不会出现异步问题。

于 2015-07-25T22:54:10.747 回答
0

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

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

于 2013-09-16T09:35:33.330 回答
0

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

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

于 2013-09-16T22:47:09.473 回答
-1

新的快速渲染包使一次性发布到客户端集合成为可能。

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

if ( Meteor.isServer ){

  FastRender.onAllRoutes( function(){
    this.find( staticData, {} );
  });
}
于 2014-01-12T04:04:48.580 回答