通知 ember-data 有关服务器更改
Posted
技术标签:
【中文标题】通知 ember-data 有关服务器更改【英文标题】:Inform ember-data about server changes 【发布时间】:2014-05-19 14:51:46 【问题描述】:我目前正在计划一个使用 ruby on rails 和 ember.js 的复杂应用程序。到目前为止,我对 ember-data 的了解是它会自动缓存记录; post.comments
将首先导致 Ajax 调用以获取给定帖子的所有 cmets,但如果用户下次访问相同的路线,它只会从存储缓存中获取记录。
问题是:如果另一个用户在这篇文章中添加了评论怎么办?如何告诉 ember 它必须重新加载它的缓存,因为某些东西发生了变化?
我已经考虑过使用 websockets 告诉客户要重新加载哪些内容的解决方案 - 但我认为这不是最佳实践。此外,我无法想象这不是一个常见问题,所以我想知道其他开发人员正在做什么来解决这个问题。
【问题讨论】:
【参考方案1】:我尝试在(实验性)聊天应用程序中实现模型更新。我在服务器端(Ruby on Rails)使用SSE:ActionController::Live
,在客户端使用EventSource
。
简化代码:
App.MessagesRoute = Ember.Route.extend(
activate: function()
if (! this.eventSource)
this.eventSource = new EventSource('/messages/events');
var self = this;
this.eventSource.addEventListener('message', function(e)
var data = $.parseJSON(e.data);
if (data.id != self.controllerFor('messages').get('savedId'))
self.store.createRecord('message', data);
);
);
App.MessagesController = Ember.ArrayController.extend(
actions:
create: function()
var data = this.getProperties('body');
var message = this.store.createRecord('message', data);
var self = this;
message.save().then(function (response)
self.set('savedId', response.id);
);
);
逻辑很简单:我从 EventSource 获取每条新记录。然后,如果记录是由另一个客户端创建的,应用程序会检测到它并使用ember-data
的createRecord
将新记录添加到存储中。假设这个逻辑可能有一些警告,但至少它可以很好地作为“概念证明”。聊天正常。
此处提供完整资源:https://github.com/denispeplin/ember-chat/
关于重新加载,我有话要说:您可能不想执行完全重新加载,这是一个消耗资源的操作。尽管如此,您的客户端仍需要某种方式来了解新记录。因此,通过 SSE 逐一获取新记录可能是最好的选择。
【讨论】:
逐个获取资源不仅耗时,而且会增加大量额外开销。不仅在客户端本地,而且在服务器端也使用了一堆额外的资源。跟踪updated_at
字段(rails 将自动管理)允许应用程序仅获取新修改的记录,并允许缓存执行它对旧记录的意义
这个问题是我的复杂网络应用程序是一种游戏,因此基于非常多的用户交互。在发生一个特定操作时跟踪我必须重新加载的确切内容已经是后端的巨大开销,并且会发生很多很多错误,我猜。
嗯,您可以使用 Pusher 或 PubNub 服务来广播消息,或者在您的服务器上安装一些 SSE 代理。 Rails 只会广播一次,但每个客户端都会收到更新。
您是否发现此解决方案在通过 SSE 传播数据更新时同样有效?我猜你的聊天相当于有人编辑了之前的评论。【参考方案2】:
如果您只是想摆脱缓存,您可以在每次用户导航到 cmets route
时强制使用 reload。但这在很大程度上取决于您要达到的目标,我希望 comments
只是一个示例。
如果您希望您的ui
随着服务器的更改自动更新,您需要与服务器进行一些通信,一些轮询机制,如websocket
或来自webworker
的轮询。然后你可以reload
从服务器发送的更改记录列表。你可能在正确的轨道上。
您也可以查看与 Ember 完美集成的 orbitjs 独立库。如果您还需要本地存储并需要管理多个数据源,这将更加有用。
【讨论】:
是的,也许我会这样做;禁用 embers 缓存/更改 embers 行为以重新加载仅显示在单个页面上的所有内容,并对始终显示的内容使用 websocket 自动更新,如在 ui 中。【参考方案3】:这确实是任何 Web 应用程序的常见问题,无论您使用什么框架。从我的角度来看,有两个主要选择。一:您有一个服务轮询服务器以检查是否有任何更改需要您重新加载某些模型,让该服务返回这些模型 ID 并刷新它们。另一个选项是您建议的,使用 websocket 并推送模型更改/新模型本身的通知。
我会选择实际上只发送评论模型本身,并将其推送到 Ember 存储和相关的帖子对象中。这将减少通过硬刷新模型来访问服务器的需要。我目前正在将此方法与我的 Ember 应用程序一起使用,其中有一个对象包含基于我的应用程序中所有模型的概览数据,并且当在后端进行更改时,我的 websocket 服务器将新的概览数据推送给我的应用程序.
更新:: 我的意思是这是一个评论,而不是一个答案,哦,好吧。
【讨论】:
【参考方案4】:我在移动应用开发方面遇到了同样的问题。虽然 websockets 似乎是第一个答案,但我担心服务器资源有限的可扩展性问题。我决定坚持使用 Ajax 调用来获取新修改的记录。这种方式只有在用户处于活动状态时才使用服务器资源。但是,正如其他人指出的那样,每次需要数据时都返回所有 cmets 会使缓存变得无用并且速度很慢。我建议更新您的 Rails 服务器以接受可选的时间戳。如果未提供时间戳,则检索每条评论。如果提供了时间戳,则仅返回 updated_at
列是 >=
提供的时间戳的 cmets。这样,如果自上次调用以来没有添加或修改任何 cmets,那么您很快就会得到一个空列表并可以继续前进。如果返回结果,您可以将它们与现有列表合并并显示更新的 cmets。
获取新创建或修改的 cmets 的示例
if params.has_key?(:updated_since)
comments = Post.find(params[:id]).comments.where("updated_at >= ?", params[:updated_since])
else
comments = Post.find(params[:id]).comments
end
【讨论】:
如果 cmets 已经加载,Ember 甚至不会发出请求。我猜,在 ember 中改变这种行为几乎没用。以上是关于通知 ember-data 有关服务器更改的主要内容,如果未能解决你的问题,请参考以下文章
EmberJS:更改加载模型的 url (ember-data)