在不丢失数据的情况下发送请求并保持时间顺序

Sending requests without losing data & keep chronological order

我有一个使用 redux saga 和 axios 发送的 reactJS webapp selecting 产品的网络请求。

它目前使用 takeEvery 作为 saga。

问题:

  1. 选择产品:如果用户 select 产品非常快(通过单击复选框),则缺少请求数据。例如:用户点击产品:a、b、c、d、e、f 但 b 和 c 不是 selected.
  2. 切换:我尝试使用 takeLatest 但如果用户 select & deselect 产品非常快,则存在竞争条件 /订单未保留。

举个例子:用户真快selects:产品a,取消了,selects了,取消了,selects了 最终状态是 'cancel' 尽管最后一个动作是 selecting 它。

它应该如何工作:

  1. 选择产品:如果用户select的产品非常快,则应正确添加所有产品。 示例:用户添加 a、b、c、d、e、f、g、h、i,因此应添加所有这些。

  2. 切换:如果用户重复快速切换某些内容,最终状态必须与最新操作相匹配

例如:用户 selects,取消,selects,取消 => 最终状态是取消 此外:用户 selects => 取消 => selects => 最终状态 id select

实现这个的适当技术方法是什么?

您可能会在不知不觉中打开一堆蠕虫,这取决于您是多么的完美主义者以及您需要您的应用程序有多可靠。如果你想要乐观的更新,天哪。

事情会变得更加困难,因为 服务器也没有响应。

您的数据库也一样,可以 run into concurrency issues and so you might want to start versioning your data

您可以使用一些策略来减少此类问题。

  • 以无状态方式编写端点或最小化发送状态的数量。例如,不发送所有选定项目的列表,只发送应切换的单个项目。

  • 利用 throttle & debounce saga 效果,它们将帮助您处理请求延迟、跳过和分发,以最大限度地减少出现问题的可能性。

  • 考虑阻止用户操作,直到您收到有意义的回复

  • 请注意,取消 saga(例如通过 takeLatest 效果)不会取消 ajax 请求本身(无论如何它仍会到达您的 BE ).它只会取消 saga 本身(换句话说,它会阻止你的应用程序在你从 BE 收到数据后 运行 代码)

  • 另请注意,使用 takeLatest 取消 sagas 是有限制的。例如。如果你只有一个实体,你可能总是想取消之前的 saga,因为之前响应的数据不再相关。

yield takeLatest(DO_ACTION, actionSaga);

但是,如果您在多个实体之上执行相同的操作,并且您只想在使用同一实体而不是另一个实体时取消之前的操作,该怎么办?如果实体列表是静态的,则可以改用函数模式:

yield takeLatest(action => action.type === DO_ACTION && action.id = 'foo', actionSaga);
yield takeLatest(action => action.type === DO_ACTION && action.id = 'bar', actionSaga);
yield takeLatest(action => action.type === DO_ACTION && action.id = 'baz', actionSaga);

一旦列表变得太长或者如果您有动态 ids/amount 个实体,您将需要使用无限循环编写自己的逻辑,id:task 映射和取消效果。

export function* dynamicIdWatcher() {
  const taskMap = {}

  while (true) {
    let action = yield take(DO_ACTION)
    if (taskMap[action.id]) yield cancel(taskMap[action.id])
    const workerTask = yield fork(actionSaga, action)
    taskMap[action.id] = workerTask
  }
}

很抱歉没有真正回答您的问题,但我希望我写的一些内容仍然可以帮助您了解用例:)