0

让我们以聊天应用程序为例。用户可以访问多个聊天线程,每个线程都有多条消息。用户界面由左侧的线程列表 ( 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组件时,可观察对象被销毁。

A如果在用户查看线程时消息到达线程BthreadList则更新(因为该订阅是实时的),但如果用户切换回线程A,则从缓存中加载消息,这些消息现在已过时,因为没有订阅将更新或使缓存无效的特定消息线程。

在用户导航到完全不同的页面的其他情况下,线程列表不会出现在视图中,问题更加明显,因为没有任何与积极订阅的聊天消息相关的内容,因此没有任何内容可以使缓存数据无效当有新消息到达时,尽管服务器理论上提供了一种通过提供新消息订阅事件来做到这一点的方法。

我的问题如下:

保持 Apollo 缓存的数据同步/无效的最佳实践是什么,这些数据并未积极“使用”?保持嵌套数据同步的最佳实践是什么(事件线程的消息 [见下文])。我觉得不必在事件查询中实现有关如何订阅和更新消息数据的逻辑是一个干净的解决方案。

使用.subscribeToMore可以使积极使用的数据保持同步,但是一旦不再使用该查询,数据就会保留在缓存中,这些数据可能会随着时间的推移而过时,也可能不会过时。当可观察对象超出范围时,有没有办法删除缓存的数据?只要至少有一个查询使用它,就保持这些数据缓存,因为我相信它还实现了基于服务器推送事件保持同步的逻辑。

是否应该使用订阅(通过 SPA 的整个生命周期)所有订阅事件并包含有关如何更新每种类型的缓存数据(如果存在于缓存中)的知识的服务?(可以通知该服务哪些数据需要保持同步以避免使用不必要的资源)(如在订阅所有newMessage事件并基于此戳缓存的服务中)?这会自动为返回的对象引用此类数据的查询发出新值吗?(更新是否message:1会使在其消息字段中返回相同的线程查询message:1自动发出一个新值)或者这些查询也必须手动更新?

这在扩展这个模型时开始变得非常麻烦,说Events也有自己的聊天线程,所以event { thread { messages { ... } }现在查询需要订阅newMessage订阅,这打破了封装和单一责任原则。订阅newMessage数据需要提供与事件关联的消息线程的 id 也是有问题的,但在查询返回之前这是不知道的。由于这个.subscribeToMore不能使用,因为那时我还没有thread_id可用的。

4

1 回答 1

0

如果预期的行为是“每次我打开一个线程时,显示最新消息,而不仅仅是缓存的内容”,那么您只需将查询设置为fetchPolicy,这将确保始终将请求发送到服务器而不是从缓存中实现。的文档缺少有关此选项的信息,但以下是React 文档的描述:threadnetwork-onlyapollo-angular

有效的 fetchPolicy 值为:

  • cache-first:这是默认值,我们总是先尝试从缓存中读取数据。如果完成查询所需的所有数据都在缓存中,则将返回该数据。如果缓存的结果不可用,Apollo 只会从网络中获取。此获取策略旨在最大限度地减少渲染组件时发送的网络请求数量。
  • cache-and-network:此获取策略将让 Apollo 首先尝试从您的缓存中读取数据。如果完成查询所需的所有数据都在缓存中,则将返回该数据。但是,无论完整数据是否在您的缓存中,此 fetchPolicy 将始终使用网络接口执行查询,这与 cache-first 不同,后者仅在查询数据不在您的缓存中时才会执行您的查询。此获取策略优化了用户获得快速响应,同时还尝试以额外的网络请求为代价使缓存数据与您的服务器数据保持一致。
  • network-only:此获取策略永远不会从缓存中返回初始数据。相反,它将始终使用您的网络接口向服务器发出请求。此获取策略优化了与服务器的数据一致性,但代价是在可用时立即响应用户。
  • cache-only:此获取策略永远不会使用您的网络接口执行查询。相反,它总是会尝试从缓存中读取。如果缓存中不存在查询的数据,则会引发错误。此获取策略允许您仅与本地客户端缓存中的数据进行交互,而无需发出任何网络请求,从而使您的组件保持快速,但这意味着您的本地数据可能与服务器上的数据不一致。如果您只对与 Apollo 客户端缓存中的数据交互感兴趣,还请务必查看 ApolloClient 实例上可用的 readQuery() 和 readFragment() 方法。
  • no-cache:此获取策略永远不会从缓存中返回您的初始数据。相反,它将始终使用您的网络接口向服务器发出请求。与仅网络策略不同,它也不会在查询完成后将任何数据写入缓存。
于 2020-05-20T11:52:01.593 回答