javascript - 如何在没有 store.dispatch 的情况下链接异步操作并等待结果

标签 javascript redux rxjs redux-observable

我正在尝试编写我的 INITIALIZE 操作,该操作应通过以下方式将一些异步操作链接在一起

  1. 调用初始化操作。
  2. 同时调用两个异步操作。
  3. 等待上述操作完成。
  4. 再运行一项操作。
  5. 完成初始化。

这是我期望的 redux 流程

INITIALIZATION_STARTED => ASYNC_ACTION_A_STARTED AND ASYNC_ACTION_B_STARTED => ASYNC_ACTION_A_FINISHED AND ASYNC_ACTION_B_FINISHED = > ASYNC_ACTION_C_STARTED => ASYNC_ACTION_C_FINISHED => INITIALIZATION_FINISHED

我设法在我的史诗中使用 store.dispatch 实现了该流程,我知道这是反模式,它将在 1.0.0 版本中删除,所以我想知道如何我可以使用纯史诗来做到这一点

我的工作解决方案

export const initEpic = (action$: ActionsObservable<Action>, store) =>
  action$.filter(actions.initialization.started.match)
    .switchMap(action => (
      Observable.forkJoin(
        waitForActions(action$, actions.asyncA.done, actions.asyncB.done),
        Observable.of(
          store.dispatch(actions.asyncA.started(action.payload)),
          store.dispatch(actions.asyncB.started(action.payload)),
        )
      ).map(() => actions.asyncC.started(action.payload))
    )
  );

const waitForActions = (action$, ...reduxActions) => {
  const actionTypes = reduxActions.map(x => x.type);
  const obs = actionTypes.map(type => action$.ofType(type).take(1));
  return Observable.forkJoin(obs);
}

我也一直在尝试使用此comment中的forkEpic像这样

export const initEpic = (action$: ActionsObservable<Action>, store) =>
  action$.filter(actions.initialization.started.match)).mergeMap(action =>
    forkEpic(loadTagsEpic, store, actions.asyncA.started(action.payload))
      .concat(
        forkEpic(loadBranchesEpic, store, actions.asyncB.started(action.payload))
      )
      .map(() => actions.asyncC.started(action.payload))
  );

但它不会调度启动操作 ASYNC_ACTION_A_STARTED_ASYNC_ACTION_B_STARTED

最佳答案

听起来merge 非常适合这个。您将开始监听 asyncA.doneasyncB.done,然后在等待期间,您将通过发出 asyncA.started 来启动请求和asyncB.started。这两个流合并为一个,因此它以正确的顺序发生,并且其中一个流发出的操作由我们的史诗发出,而不需要 store.dispatch

const initEpic = action$ =>
  action$.filter(actions.initialization.started.match)
    .switchMap(action => (
      Observable.merge(
        waitForActions(action$, actions.asyncA.done, actions.asyncB.done)
          .map(() => actions.asyncC.started(action.payload)),
        Observable.of(
          actions.asyncA.started(action.payload),
          actions.asyncB.started(action.payload),
        )
      )
    )
  );

这是一个 JSBin 演示:https://jsbin.com/yonohop/edit?js,console

它不会执行任何 ASYNC_ACTION_C_FINISHEDINITIALIZATION_FINISHED 内容,因为该问题的代码未包含在问题中,因此不确定它会做什么。 😁

您可能会注意到这主要是一个常规的 RxJS 问题,其中流发生的项目是操作。这确实很有帮助,因为当您寻求帮助时,您可以向整个 RxJS 社区询问您是否将问题设计为通用 RxJS。

<小时/>

请注意,我在开始之前监听了完成;这通常是最佳实践,以防 donestarted 之后同步发出。如果你不先听,你就会错过它。由于它是异步的,所以并不重要,但通常仍然是最佳实践,并且在单元测试时很有帮助。

关于javascript - 如何在没有 store.dispatch 的情况下链接异步操作并等待结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47000384/

相关文章:

javascript - 视口(viewport)始终集中在更大的背景图像上

javascript - 如何使用 jquery 删除 br?

javascript - Redux 调度一个包含要从 reducer 调用的方法的操作

javascript - 页面重新加载后无法从 redux 存储中获取数据

error-handling - rxjs-最终处理异步错误

javascript - 我如何在类组件中使用 bool 状态的可重用函数

javascript - 一个表单怎么可能调用多个js函数呢?

javascript函数名称后的两个括号

javascript - .first() 运算符影响其他订阅

javascript - 嵌套 Observables 在 Ionic2/Angular2 应用程序中表现不同