如何确保在执行下一个史诗之前完成一个史诗?

How to make sure one epic is completed before executing the next epic?

这是我们升级到版本 1.x 后在我们的应用程序中遇到的问题,他们在当前堆栈完成后 (https://github.com/redux-observable/redux-observable/pull/493) 引入了调度 epic 的排队操作。

想象一个动作 (INIT_STUFF),它有一个史诗,其中 return 是一个动作列表(按 INIT_AINIT_B 的顺序)。这些行动中的每一个都有自己的史诗。他们在那里做了一些事情,return 一个修改商店的动作。

在 redux-observable 的先前版本中,INIT_B 的史诗可能依赖于 INIT_A 的史诗已完成执行并对商店进行更改这一事实。然后这部史诗可以使用更新后的商店。

在最新版本中,INIT_AINIT_B 的 epics 都按各自的顺序执行,但是它们 return 的操作(即修改商店)被推迟到最后一个史诗完成。这意味着 INIT_B 的史诗无法访问 INIT_A 所做的商店更新。

下面是我所说内容的简单实现:https://redux-observable-playground-ip3qfb.stackblitz.io

对于这样的用例,迁移路径可能是什么?

这个确实有难度。就我个人而言,我认为有两个 epics 需要依赖这样的东西将是一个 anti-pattern,特别是因为它们都是同步的。我认为这不仅仅是因为它是人为设计的,否则我认为你不会遇到这个问题。

如果史诗 B 确实应该等到史诗 A 准备就绪后才开始,那么 parent (initializeStuffEpic) 应该确保执行此序列,或者史诗 B 可以监听一些信号以了解 A 已准备就绪因为 Epics “不应该”像这样泄露它们的实现细节。或者,这可能表明逻辑不应该是两个独立的 Epics 而只是一个,使用函数组合来保持组织有序。

Epics 通常将动作作为信号响应,尽管第二个参数 state$ 也是一个 Observable,也可以订阅。如果你真的喜欢这样做,我认为这可能是最简单的方法:

https://stackblitz.com/edit/redux-observable-playground-g1nuis?file=initialize.js

export const initBEpic = (action$, state$) =>
  action$.pipe(
    ofType("INITIALIZE_B"),
    mergeMap(({ payload }) => {
      return state$.pipe(
        filter(state => state.initialized.A), // Wait until it is indeed true
        take(1), // Very important!
        map(() => ({
          type: "IS_B_READY",
          payload: true
        }))
      );
    })
  );

与大多数事情一样,有一些注意事项。如果 A 从未准备好怎么办?

--

在 redux-observable v1.0 中对操作的安排方式所做的更改旨在使某些事情更加直观,同时阻止其他一些不良模式。在那个决定中没有考虑这个特定的模式,所以我不完全确定我是否会改变行为以使您的用例更容易。不幸的是,虽然这看起来很明显是行不通的,但这可能是一个可以接受的权衡,因为这是我第一次看到这个。

将 Epics 几乎视为独立的进程(尽管它们不是。)在没有实际信号(动作或状态 $ 更新。)

我们总是有机会为 v2 更改它,但是需要有人针对特定更改提出建议或 PR,而调度的工作方式——QueueScheduler 的内部实例——有点复杂。