首页 文章

阿波罗突变去抖和竞争条件

提问于
浏览
5

(这是对https://github.com/apollographql/apollo-client/issues/1886的跟进)

我正在尝试构建一个文本输入,它将在用户输入时更新值 .

第一次尝试

我首先尝试使用 optimisticResponse 来更新用户输入的本地缓存 . 这是有效的,除了它会在每次击键时触发突变 . 除了通过请求充斥网络之外,还存在网络不一致的问题 . 最后一个突变可能首先到达,第一个突变最后到达 . 这导致服务器以过时值结束 . 以下是此竞争条件的示例:

type: a
mutate request: a
type: b
mutate request: ab
arrives on server: ab
arrives on server: a

现在服务器在graphql中记录了“a”,这是不正确的 .

添加去抖动

为了缓解这个问题,我对按键事件进行了辩论 . 虽然这确实有助于上述竞争条件,但它并没有解决它 . 如果网络比你的去抖阈值慢,那么仍有可能出现竞争条件 .

因为我们现在正在对文本输入进行去抖动,所以我们需要向该React组件引入一个本地状态,以便在用户输入时立即更新(如github问题中建议的@jbaxleyiii) . 现在我们的状态位于两个位置(组件状态和apollo缓存) .

这个问题的一个大问题是组件在收到新道具时不会更新 . 例如 . 当graphql更新并推送到客户端时 .

添加网络队列

因为debounce实际上并没有解决竞争条件,所以我添加了一个网络队列(除了去抖动),它将管理变异请求,以确保一次只有一个变异 . 如果在飞行中有一个突变请求时它会收到突变请求,它会将它排队等待第一个返回时被触发 . 如果已经有一个排队的突变,它将丢弃它并将其替换为新的突变(一次只能有一个项目在队列中) . 这是一个例子:

type: a
send mutate request: a
type: b
queues mutate request: ab     <<  wait to send this until "a" comes back
type: c
replaces queued request: abc  << discard the queued request for "ab", it's old now
response from server: a
send mutate request: abc      << send the queued mutation and clear the queue
response from server: abc

这保证了我们不会有竞争条件(至少来自这个客户......)

但是这种方法存在问题 . optimisticResponse 只会在突变发生时更新 . 如果正在进行突变,我们需要在应用更新_1805448之前等待网络返回 . 在慢速网络上这段时间可能很长 . 因此,在上面的示例中,我们不能使用 optimisticResponse 更新到"abc",直到"send mutate request: abc" .

这不是一个大问题,只是一个延迟,但它似乎是我们应该能做的事情 .

尝试在用户键入时更新缓存

在文档中,我了解到我可以使用 withApollo 来访问客户端,并在用户通过 writeQuery 键入时更新缓存 . 这取代了 optimisticResponse 的需要 . 但是,当旧的响应返回并从我们下面更新缓存时,就会出现问题 . 这是一个例子:

action                   | cache
-------------------------+------------
type: a                  | a
mutate request: a        | a
type: b                  | ab
queues request: ab       | ab
response from server: a  | a  << oh no!
mutate request: ab       | a  << we're not using optimisticResponse anymore
... network time ...     | a
response from server: ab | ab

我想我们可以使用 client.writeQuery 来更新缓存作为用户输入,并且 optimisticResponse 在mutate请求触发时更新,但现在这个代码现在变得非常难以遵循 .

也许有一种方法可以在 update 函数中处理这个问题,但我还没有走得那么远 .

帮助?

我对阿波罗很新,所以也许我错过了什么 . 是否有更好的方法来处理阿波罗的许多快速突变?

1 回答

  • 1

    每个突变都会返回一个promise,因此您可以通过跟踪最新的突变来了解无序突变何时到达 .

    由于您接受用户键入的任何内容,这意味着用户的值是规范的,并且您实际上不需要乐观响应 . 您所做的只是确保服务器具有与您相同的 Value .

    所以我建议你跟踪Redux中的输入并添加一个触发突变的商店监听器(带去抖动) .

    如果确实需要跟踪服务器值,请使用计数器查看返回的变异是否为最后一个(将变量存储在变量发送中,并将该值与变异返回时的计数器值进行比较) .

相关问题