Publish/subscription Meteor 1.2.0.1 问题

Publish/subscription issue with Meteor 1.2.0.1

在 Meteor 应用程序中,发布到服务器上集合的数据不会出现在客户端中。

从默认的 Meteor 应用程序开始,我已将默认的 JavaScript 文件更改为以下内容:

Test = new Mongo.Collection("test")

if (Meteor.isClient) {
  Meteor.subscribe("test")
  console.log(Test.find({}).fetch())
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    Meteor.publish("test", function () {
      var cursor = Test.find({})
      var result = cursor.fetch()
      console.log(result)
      console.log(JSON.stringify(result))
      return cursor
    })

    var selector = {}
    var modifier = { key: "value" }
    var options = {}
    var callback = function (error, data) {
      console.log("Test", error, data)
    }
    Test.upsert( selector, modifier, options, callback )
  });
}

在服务器终端中,我可以看到一个文档已添加到测试集合中,并且该集合现在包含一个文档,但是 console.log(Test.find({}).fetch()) 在浏览器中的输出是 [].

这是服务器的典型输出:

I20150924-14:38:59.313(-4)? Test null { numberAffected: 1 }
=> Meteor server restarted
I20150924-14:38:59.404(-4)? [ { _id: 'e3B6js9xq3pbspego', key: 'value' } ]
I20150924-14:38:59.405(-4)? [{"_id":"e3B6js9xq3pbspego","key":"value"}]

从浏览器:

Navigated to http://localhost:3000/
[]                   mongoTest.js:5 

我错过了什么?

这是预料之中的,因为 subscribe 不会阻止浏览器的执行。订阅开始后,Test.find() 在文档到达客户端之前执行。这是一个应该打印结果的实现:

if (Meteor.isClient) {
  Meteor.subscribe('test', function() {
    console.log(Test.find({}).fetch());
  });
}

更稳健的解决方案是使用 autorun,因为它避免了添加第一个文档时的任何竞争条件:

var handle = Meteor.subscribe('test');

Tracker.autorun(function() {
  if (handle.ready())
    console.log(Test.find({}).fetch());
});

推荐阅读:common mistakes的"subscriptions don't block"部分。

在客户端代码中添加Tracker.autorun(...)解决问题:

if (Meteor.isClient) {
  Tracker.autorun(function () {
    Meteor.subscribe("test")
    console.log(Test.find({}).fetch())
  })
}

浏览器控制台中的输出现在是:

Navigated to http://localhost:3000/
[]                   mongoTest.js:6
v [Object]           mongoTest.js:6
  > 0: Object
      _id: "e3B6js9xq3pbspego"
      key: "value"
    length: 1
  > __proto__: Array[0]

显然 Test.find({}).fetch() 在客户端第一次连接到服务器时发现一个空集合,然后服务器有时间更新客户端上的集合。