为什么observe()不能在服务器上同步执行?
问题描述:
在客户端插入(更新,删除...)集合时,本地观察者将同步触发,即在本地模拟插入效果时触发。这意味着后面的代码可以依赖于插入的所有副作用而不存在竞态条件。为什么observe()不能在服务器上同步执行?
服务器上的行为似乎有所不同:观察者似乎异步触发,插入回调可能在观察者执行之前返回。这使得正确同步代码变得更加困难:我无法找到一个可靠的方法来判断插入的所有副作用何时发生。除了在客户端上,这会在插入操作后直接依赖副作用时创建争用条件,并且在客户端和服务器之间共享代码变得更加困难。
这是预期的行为?在服务器端有没有一个很好的解决方法来告诉所有观察者何时执行? (我的用例:我有一个“命令”表,我需要撤消/重做。插入一个新命令将触发对本地非同步集合的更改,即命令从观察者内部执行。后续命令要求对本地集合的更改完成,否则将失败。)
答
我在meteor-talk group中找到了答案。相应的代码注释可以发现here:
// After making a write (with insert, update, remove), observers are
// notified asynchronously. If you want to receive a callback once all
// of the observer notifications have landed for your write, do the
// writes inside a write fence (set Meteor._CurrentWriteFence to a new
// _WriteFence, and then set a callback on the write fence.)
以防万一你想知道,看起来在实践中 - 这是我做(在CoffeeScript中):
Future = __meteor_bootstrap__.require('fibers/future')
...
future = new Future
fence = new Meteor._WriteFence
fence.onAllCommitted ->
fence.retire()
future.ret()
result = Meteor._CurrentWriteFence.withValue fence, ->
# do something that triggers observers
...
return result
fence.arm()
future.wait() # This will return only /after/ all observers fired.
...
这是一个未记录的功能,而不是保证从长远来看能够工作。因此,如果核心团队想要描述官方解决方案,我的问题仍然存在。
这是延迟补偿投入行动。为了避免它,你可以使用'Meteor.call'和'Meteor.methods'。如果客户端/服务器由于某种原因未同步,则该操作在客户端反转,并且在回调中引发错误。我也问过类似的问题http://stackoverflow.com/questions/14800971/meteor-latency-compensation-and-hinting-completion-commit-to-the-user – Akshat 2013-02-10 22:36:48
@Akshat:这个问题不是关于延迟补偿或同步客户端和服务器。它是关于node.js中的异步代码执行(仅限于服务器)与浏览器中的同步代码执行(仅限客户端)。 Meteor通常使用光纤来“模拟”服务器上的同步行为。但在这里观察员看来并不是这样。我怀疑这是我忽略的一个很好的理由。 – jerico 2013-02-11 00:09:41
是的,我看到你已经编辑了这个问题来澄清这个问题,你能提供你用来显示这种情况的代码吗? – Akshat 2013-02-11 00:11:55