Apollo-link: [apollo-link-offline] 你有什么想法?

创建于 2017-10-05  ·  38评论  ·  资料来源: apollographql/apollo-link

您好,我很乐意参与此功能构建。 因为我现在的项目真的需要它。 但我需要一些提示才能开始。 有没有人有任何想法?

enhancement

最有用的评论

嘿伙计们,我试图拼凑一个基本的 react-native 实现,它具有与apollo-offline相似的行为。
(ping https://github.com/Malpaux/apollo-offline/issues/14)

您可以在此要点中查看: https :

它是以下各项的组合:

当设备离线时,请求将排队,当它重新上线时将取消排队。 ( apollo-link-queue )

任何因网络错误而失败的请求都将被重试(目前是无限次)。 ( apollo-link-retry )
请注意,这可能是因为设备离线,或者后端根本无法访问(例如,如果它已关闭)。

但是,如果我们可以从缓存中解析查询,则不会重试,而是将缓存中的数据用作响应。 这是在optimisticFetchLink函数中实现的。

在我看来,这种“乐观获取”行为是 apollo-offline 最重要的部分之一,任何未来的apollo-link-offline实现都应该支持这一点。 这使用户能够在离线时照常使用该应用程序,只要数据已在某个时间点被获取和持久化。 在我看来,这应该是network-and-cache fetch policy 的默认行为,但不幸的是,这看起来不会很快改变(请参阅 https://github.com/apollographql/react-apollo/issues/ 604#issuecomment-355648596)。

如果将要点保存为offlineLink.js ,则可以按如下方式使用它:

import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'

// get this from https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d
import { createOfflineLink } from './offlineLink'

const cache = new InMemoryCache()
const networkLink = createHttpLink()

const offlineLink = createOfflineLink({ cache })

const link = ApolloLink.from([
  // ... + other links ...
  offlineLink,
  networkLink,
])

const client = new ApolloClient({
  cache,
  link,
}

已知问题/缺失位

  • 目前这只适用于 react-native。 isOnline检查应该被抽象掉以使这个跨平台。
  • 如果您在缓存中只有部分响应,您将在后面的某处收到一个被拒绝的承诺,告诉您响应不完整。 我还没有研究如何解决这个问题,或者 apollo-offline 如何解决这个问题。 如果您想尝试解决此问题,我将不胜感激。
  • 您目前无法更改任何重试设置 - 这应该作为额外的配置参数添加。
  • 您无法控制乐观获取。 您应该能够为每个查询独立设置它。 我不是 apollo-offline 实现这个的忠实粉丝(设置{__online_: true}查询变量),但肯定应该有某种方法可以做到这一点。
  • 显然也没有测试。

我很感激任何正在寻找解决方案的人来尝试一下,然后我们可以将它变成一个合适的 npm 模块,其中包含类型、测试、文档和所有内容。 在我看来,这种行为非常重要,而且 apollo-client 2 对此还没有适当的解决方案,这真是令人遗憾。

不错的✌️

所有38条评论

您认为典型的用例是什么?

作为离线应用程序:

  • 所有 graphql 请求都添加到队列中。 (可以存储在缓存中)。
  • 当应用程序收到在线信号时,它会通知链接重新提交之前的请求。

我想它是这样使用的:

import { NetInfo } from 'react-native';
import OfflineLink from 'apollo-link-offline';

const offlineLink = new OfflineLink({
  isOnlineAsync: () => NetInfo.isConnected.fetch(),
});

NetInfo.isConnected.addEventListener('change', (isConnected) => {
  if (isConnected) {
    offlineLink.resubmit();
  }
});

我认为这将是一个了不起的功能。 我认为它可能发生的方式是让 Apollo-link-offline 定义一组需要离线使用的查询和突变。

一旦定义了这些,在应用程序的后台,我们就可以从查询中获取所有数据并将它们存储在本地存储中。 对于 Mutations,我们需要在本地存储中创建的所有字段,以便我们可以存储任何离线创建的数据。

这样我们仍然可以在离线时执行功能,同时将数据存储在本地缓存中。
如果我们可以链接到 Service Workers,我们也会通过 Google 的 PWA 测试
然后当应用重新上线时,本地缓存上发生的所有变化都可以传递回 API。

显然,需要某种形式的并发保护。

我担心的是用户 A(离线)更新了表 X,而用户 B(在线)在用户 A 离线时更新了表 X。 我们在这里需要某种形式的并发规则。 我想它可能是日期驱动的,但如果用户 A 在用户 B 不知道的情况下覆盖用户 B 的数据,它并不能解决问题。

或者我们可以让 Mutation 失败,让用户在重新上线时手动更新。

Apollo Client 2 很棒,但这个功能绝对是狗屁

我也会是这个的忠实粉丝。 我知道在使用 1.0 的 Redux 商店解决这个问题方面有不同的尝试,但是以一致的方法使其成为 Apollo 2.0 生态系统的完整公民将是非常了不起的。

这里介绍的大部分内容对我来说已经很有意义了——基本上我想将我的数据持久化到本地存储,然后在事后将它从那里拉到 Apollo 中。 其次,排队突变。

作为第三级目标,能够在后台吸收更多数据也很棒,无论如何我都会想做一些事情。 我实际上也想在本地存储几乎所有用户的数据,只是为了使常见的查询操作更快,然后再水化以获得完全准确性,网络允许。 因此,针对这种急切加载的角度的某种解决方案会很棒,特别是当 Service Workers 开始变得可行时,Safari 最终将它们纳入技术预览。

我也对此感到兴奋。 @danieljvdmapollo-client repo中的一个问题的持久性方面取得了一些领先。

我认为RetryLink对管理网络错误和重试很有用,尽管我希望看到某种类似 redux-offline had

这很酷。 @2WheelCoder引用的问题是一种早期且可能是幼稚的方法,更适合持久化缓存而不是完全离线支持(排队查询/突变等)。

它仍然可能是一个不错的起点和基础。 我在那个问题中指出的是,我目前没有一个很好的方法来监控缓存的变化。 实际上,我今天早些时候尝试实施@2WheelCoder的初步建议,但遇到了类似的问题。 为“监视存储更改”创建 ApolloLink 的问题在于它仅存在于客户端操作和后续缓存写入之间的上下文中。 所以我可以在请求发出之前拦截它(中间件)并在它被写入缓存之前拦截它(后件)但我不知道它何时被写入 - 我只能猜测(我目前的黑客是 1000ms 超时)。

使用链接进行离线持久化的另一个致命缺陷是它没有考虑订阅。 订阅链接只会在订阅打开时触发,而不是在后续事件中触发(也许有一种方法可以做到这一点,但我错过了?)。

这基本上就是我现在所处的位置,而且我很困惑 - 我认为要进一步了解我可能需要打开一个 PR 到 apollo-cache-inmemory。

@danieljvdm我在同一个地方,我认为在遇到同样的问题后直接在缓存上处理持久性确实有意义。 HttpLink 只是不适合它,因为 observable 在请求之后但(通常)在缓存更新之前完成。

虽然在 apollo-cache-inmemory 上打开 PR 可能值得,但我也想知道将它分叉到一个新项目中是否更好。 Apollo 2 围绕缓存和链接的模块化似乎表明,如果您需要不同类型的缓存,您可以构建它。 也许 apollo-client 上的问题是下一步(我不认为 apollo-cache-inmemory 有自己的 repo)?

很抱歉从这里的链接中获得了一点题外话。

@holman你有关于 safari 技术预览中服务工作者的参考吗?

@sedubois它在一两个月前下降了(有点突然)。 它处于技术预览阶段,但还有很多工作要做

@2WheelCoder我喜欢将 PR 用于 apollo 客户端以获得新缓存的想法。 也许apollo-offline-cache可以扩展apollo-cache-inmemory ? 我愿意帮助解决这个问题。 想在那里打开一个问题?

@2WheelCoder @danieljvdm如何使用 LocalForage 进行持久化https://github.com/localForage/localForage如果你们打开 PR,我愿意伸出援手

@danieljvdm是的,如果你想获得公关,我会打开一个问题。 在接下来的半周内我没有太多时间,但很高兴在那之后加入。

@Eishpirate绝对同意 LocalForage 很棒。 我认为 redux-persist 管理保存商店的方式非常可靠,可能可以作为apollo-offline-cache遵循的体面模式。

伙计们,我正在使用 redux 持久包将存储数据保存在本机 AsyncStorage 中。 我现在怎么做? 任何的想法?

@Eishpirate :localforage 是否适用于本机反应? 查看库的兼容性图表,我找不到有关 react native 的任何信息。 https://github.com/localForage/localForage/wiki/Supported-Browsers-Platforms

如果 apollo 的离线功能不适用于应用程序,那将是非常难过的。

@timLoewel这是一个很好的观点。 没想到像 React Native 那样超前。 不要相信它是明确的。

这可能会进一步导致意外问题。 不确定是否有可行的替代方案而不必重新发明轮子

可能与此讨论相关的有趣文章https://blog.logrocket.com/building-an-offline-first-app-with-react-and-rxdb-e97a1fa64356?t=now

使用 rxdb 作为离线数据库看起来非常有前途。 这与 React、React-Native、Vue、Angular 以及几乎最受欢迎的选项兼容。

但我发现的问题是它需要与像 PouchDB(CouchDB 的衍生物)这样的 noSQL 数据库同步。 在我的用例中,我使用的是关系 SQL 数据库 (Postgres),并且我所有的数据验证都发生在数据库级别。 如果我必须使用这个系统,那么我需要通过 jsonschema 维护验证。

它不遵循 DRY 原则,并且肯定会引入问题。

我发现的另一个选项是 Kinto http://docs.kinto-storage.org/en/stable/index.html ,它与 Postgres 一起使用,因此应该避免 rxdb 会引入的一些额外的复杂层。 Kinto 使用 HTTP,因此理论上我们可以将其插入 Apollo-link-http https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http

听起来很多工作都与缓存有关。

还原度怎么样? (我是认真的)

一个apollo-link-offline包,基于apollo-offline工作和...
apollo-cache-redux包。 像 apollo-offline 现在一样使用 redux-offline/redux-persist。

Apollo 创建了 inmemory-cache 作为默认的通用解决方案 - 我可以理解为什么他们不想与另一个库如此紧密地联系在一起。 但是 redux/redux-offline/redux-persis 解决方案是经过实战考验的……它仍然是一个不错的选择。 三者的发展都非常活跃。

编辑: apollo-cache-redux现在存在,感谢@rportugal

@giautmapollo-link-queue 。 如果你们中有任何人有改进的想法,我很乐意得到你们的建议或贡献。

请问这个问题是什么状态? 是否有一些东西可以用于来自 Apollo 且与 Redux Offline 无关的离线内容?

@smithaitufe ,
是的,您可以使用apollo-cache-persist

@Gregor1971
感谢您的参考。 我会尝试一下并提交我的观察结果。
从表面上看,它看起来很酷且易于实现。

这与apollo-link-queue 有何不同

嘿伙计们,我试图拼凑一个基本的 react-native 实现,它具有与apollo-offline相似的行为。
(ping https://github.com/Malpaux/apollo-offline/issues/14)

您可以在此要点中查看: https :

它是以下各项的组合:

当设备离线时,请求将排队,当它重新上线时将取消排队。 ( apollo-link-queue )

任何因网络错误而失败的请求都将被重试(目前是无限次)。 ( apollo-link-retry )
请注意,这可能是因为设备离线,或者后端根本无法访问(例如,如果它已关闭)。

但是,如果我们可以从缓存中解析查询,则不会重试,而是将缓存中的数据用作响应。 这是在optimisticFetchLink函数中实现的。

在我看来,这种“乐观获取”行为是 apollo-offline 最重要的部分之一,任何未来的apollo-link-offline实现都应该支持这一点。 这使用户能够在离线时照常使用该应用程序,只要数据已在某个时间点被获取和持久化。 在我看来,这应该是network-and-cache fetch policy 的默认行为,但不幸的是,这看起来不会很快改变(请参阅 https://github.com/apollographql/react-apollo/issues/ 604#issuecomment-355648596)。

如果将要点保存为offlineLink.js ,则可以按如下方式使用它:

import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'

// get this from https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d
import { createOfflineLink } from './offlineLink'

const cache = new InMemoryCache()
const networkLink = createHttpLink()

const offlineLink = createOfflineLink({ cache })

const link = ApolloLink.from([
  // ... + other links ...
  offlineLink,
  networkLink,
])

const client = new ApolloClient({
  cache,
  link,
}

已知问题/缺失位

  • 目前这只适用于 react-native。 isOnline检查应该被抽象掉以使这个跨平台。
  • 如果您在缓存中只有部分响应,您将在后面的某处收到一个被拒绝的承诺,告诉您响应不完整。 我还没有研究如何解决这个问题,或者 apollo-offline 如何解决这个问题。 如果您想尝试解决此问题,我将不胜感激。
  • 您目前无法更改任何重试设置 - 这应该作为额外的配置参数添加。
  • 您无法控制乐观获取。 您应该能够为每个查询独立设置它。 我不是 apollo-offline 实现这个的忠实粉丝(设置{__online_: true}查询变量),但肯定应该有某种方法可以做到这一点。
  • 显然也没有测试。

我很感激任何正在寻找解决方案的人来尝试一下,然后我们可以将它变成一个合适的 npm 模块,其中包含类型、测试、文档和所有内容。 在我看来,这种行为非常重要,而且 apollo-client 2 对此还没有适当的解决方案,这真是令人遗憾。

不错的✌️

@smithaitufe ,

这与 apollo-link-queue 有何不同?

看起来 apollo-link-queue 根据连接状态做智能事情。 apollo-cache-persist 保存缓存; 例如,允许用户在断开连接时启动和运行您的应用程序。 如果不保留缓存,您的应用程序将需要连接才能启动,

我们可能同时需要,或者更好的是, @lachenmayer上面的解决方案(使用 apollo-link-queue)和一个持久的缓存。 (我们在链接存储库中聊天,所以这里的大部分重点都在此)

@lachenmayer 乍一看,您的方法看起来非常吸引人。

我完全同意你的看法,比如apollo-offline的乐观获取功能的必要性。 它(或者更确切地说是缺乏它)很大程度上是激励我开始apollo-offline

我自己对如何在apollo-offline选择性地启用/禁用乐观获取功能不太满意。 查询变量不是首选,但它们似乎是最实用的。 你会提出什么建议?

接下来的几周对我来说压力很大。 在那之后,我非常乐意为 Apollo 的最新离线第一个解决方案的实现做出贡献 - 可能是apollo-offline包的新版本或类似apollo-link-offline东西

谢谢@MLPXBrachmann!
我觉得应该使用fetchPolicy控制乐观获取 - 如果我不想从缓存中获得任何东西,我应该能够使用network-only

@lachenmayer @MLPXBrachmann

我已经准备好并愿意做出贡献。

我也在寻找在 Apollo 应用程序中实现离线行为的选项。 @lachenmayer的方法看起来非常有前途,但是由于它依赖于 apollo-link-retry,因此不会持久应用未成功应用的更改,因此如果刷新页面,则任何未提交到服务器的数据都将被丢弃(如果应用程序被暂停,我认为这在 react-native 上也是一样的)。 在这方面是否有任何工作或至少讨论?

@nicocrm我明白了……目前关于离线支持的讨论主要集中在这个问题上。 我认为阿波罗现在有其他优先事项,所以我们应该创建一个社区项目apollo-link-offline 。 这有望导致比现在更多的讨论和进展😄

@benseitz我绝对赞成。 对该功能有很多兴趣,所以我确信社区项目有空间 - 只要我不重复或分散现有的工作,我就可以为 apollo-link-offline 创建一个新团队和 repo 并邀请所有感兴趣的人. 我有一些个人兴趣以及一个真正推动该功能的客户,所以我将有几个小时的时间来处理它。 我会在 apollo-offline repo 上询问,看看他们是否想带头,因为他们有更多的经验。

我当然对此也有个人兴趣 - 很乐意在此@nicocrm 上与您进一步交谈。 到目前为止,我还没有注意到在 react-native 上有任何丢失的请求,但是我还没有真正正确地测试过所有这些东西(到目前为止只使用查询并且它_似乎_可以很好地运行所有东西)。

我觉得为此开始一个回购是有意义的。 构建apollo-offline @MLPXBrachmann上面提到他在接下来的几周内没有时间花在改进apollo-offline上,我认为将其称为apollo-link-offline确实最有意义

我认为没有任何代码可以从apollo-offline重用,因为它非常特定于 redux。

@nicocrm我非常同意你的看法。 持久排队查询/突变绝对应该是潜在的apollo-link-offline处理的事情。

@benseitz我也认为将apollo-link-offline作为社区努力开始是一个好主意,并且非常希望参与其开发。

@lachenmayer您说得对, apollo-offline和计划中的apollo-link-offline包共享的代码量可能几乎为零。 然而,我确实认为,在 Apollo 2.0 宇宙中开发离线工具包时,前者的许多基本概念仍然适用。

无论如何,我很乐意讨论apollo-link-offline想法,提供有关实施的反馈,并且 - 一旦我的日程安排空闲了一点 - 也贡献一些代码。

@MLPXBrachmann @lachenmayer @nicocrm这听起来是正确的方法!
由于任何人都可以在Apollo Slack上打开公共频道。 我建议打开一个名为apollo-link-offline 。 也许这让我们之间的交流更容易一些。 所有重要的决定仍应记录在 GitHub 问题中。

你同意我同时打开 repo 和 slack 频道,或者你们中的一个人想要这样做吗?

肯定的,谢谢!

我将你们三个添加为Repo 的合作者。 你可以加入Apollo Slack#apollo-link-offline频道

当然邀请大家在 GitHub Repo 上进行协作并在 Slack 上讨论 :)
我很兴奋💯

对于那些通过 Google 搜索来到这里的人,我已经为 Apollo Client 2.0 编写了今天可用的所有现有离线技术的摘要。

https://github.com/benseitz/apollo-link-offline/issues/1#issuecomment -371678922

Apollo 是否正在开发等效的 AWS AppSync? 我们已经有一个 GraphQL 服务器,需要使用我们的服务器而不是 AWS 解决方案(即 Lamda、DynamoDB、Elastic Search)为查询和突变进行离线客户端缓存。

希望它工作。

@masull那绝对是惊人的。 我尝试过,但并不认为 firebase 或 parse 平台对我有用,所以拥有这个功能会很棒。
很难用很多包来设置所有东西......一点都不好玩:)

此页面是否有帮助?
0 / 5 - 0 等级