让我们以聊天应用程序为例。
用户可以访问多个聊天线程,每个聊天线程都具有多个消息。
用户界面由左侧(listThreads
)上的线程列表组成,其中包含另一方的名称,最后一条消息,未读消息计数以及最后一条消息的日期和时间以及实际的消息(viewThread
)和右侧的回复框(想想Facebook Messenger)。
当用户选择消息线程时,viewThread
组件按照以下方式订阅查询:
query thread {
threads(id: 'xxxx') {
id
other_party { id name }
unread_messages
messages {
sent_by { id }
timestamp
text
}
}
要进行实时更新,请设置q.subscriptToMore
并按以下方式进行订阅:
subcription newMessages {
newMessage(thread_id: 'xxx') {
sent_by { id }
timestamp
text
}
}
这很好用,新消息按原样显示。
要列出可用的消息线程,请查询所有线程的不太详细的视图:
query listThreads {
threads {
id
other_party { id name }
unread_messages
last_updated_at
}
}
为使列表保持同步,使用了相同的订阅,而没有在thread_id
上进行过滤,并且线程列表数据是手动更新的
这也很好。
但是,如果选择了线程A
,则会缓存线程A
的消息。
如果此后选择了线程B
,则将破坏获取线程A
的详细信息的查询订阅,因为当路由器交换viewThread
组件时,observable被破坏了。
如果当用户正在查看线程A
时,如果消息到达线程B
,则threadList
被更新(因为订阅已生效),但是如果用户切换回线程A
中,消息已从缓存中加载,这些消息现在已经过时,因为没有特定消息线程的订阅会更新或使缓存无效。
在其他情况下,用户导航到一个完全不同的页面,在该页面中看不到线程列表,该问题甚至更加明显,因为没有任何与活动订阅的聊天消息相关的内容,因此也没有任何无效的消息尽管从理论上说服务器是通过提供新的消息订阅事件来实现此目的的,但是当新消息到达时,缓存的数据仍会保留。
我的问题如下:
由Apollo缓存的,未积极“使用”的数据保持同步/无效的最佳实践是什么? 使嵌套数据保持同步(事件线程的消息[见下文])的最佳实践是什么?我不想在事件查询中实现关于如何订阅和更新消息数据的逻辑是一个干净的解决方案。
使用.subscribeToMore
可保持主动使用的数据同步,但是一旦不再使用该查询,数据将保留在高速缓存中,这可能会或可能不会随着时间而过时。当可观察对象超出范围时,是否可以删除高速缓存的数据?与之一样,只要至少有一个查询在使用该数据,就保留它的高速缓存,因为我相信它还实现了根据服务器推送事件保持同步的逻辑。
是否应该使用一项服务(在SPA的整个生命周期内)订阅所有订阅事件,并包含有关如何更新每种类型的缓存数据(如果存在于缓存中)的知识? (可以通知该服务有关哪些数据需要保持同步以避免避免使用比必要数量更多的资源)(例如在订阅所有newMessage
事件并以此为基础缓存的服务中)?对于返回了引用了此类数据的对象的查询,是否会自动为其发出新值? (更新message:1
会使在其消息字段中返回相同的message:1
的线程查询自动发出新值)还是必须手动更新这些查询?
当使用说说Events
扩展这个模型并且也有自己的聊天线程时,这变得非常麻烦,因此查询event { thread { messages { ... } }
现在需要订阅newMessage
订阅,这将破坏封装以及单一责任原则。
订阅newMessage
数据还需要提供与事件关联的消息线程的ID,但这在查询返回之前是未知的,这也是一个问题。由于此.subscribeToMore
无法使用,因为那时我还没有thread_id
。