如何链接异步操作并在没有store.dispatch

时间:2017-10-29 12:53:58

标签: javascript redux rxjs redux-observable

我试图编写我的INITIALIZE操作,该操作应按以下方式将某些异步操作链接在一起

  1. 调用初始化操作。
  2. 同时调用两个异步操作。
  3. 等待上述操作完成。
  4. 再次执行一项操作。
  5. 完成初始化。
  6. 这是我期望的redux流程

    INITIALIZATION_STARTED => ASYNC_ACTION_A_STARTEDASYNC_ACTION_B_STARTED => ASYNC_ACTION_A_FINISHEDASYNC_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

1 个答案:

答案 0 :(得分:1)

merge之类的声音非常适合这一点。您将开始倾听asyncA.doneasyncB.done,然后等待您,通过发出asyncA.startedasyncB.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。

请注意,我在开始前听完了;如果在done之后同步发出started,这通常是最佳做法。如果你没先先听,你就会错过它。由于它不同步它并不重要,但通常仍然是最佳实践,并且在您进行单元测试时非常有用。