如何在没有 store.dispatch 的情况下链接异步操作并等待结果
How to chain async actions and wait for the result without store.dispatch
我正在尝试编写我的 INITIALIZE
操作,它应该按以下方式将一些异步操作链接在一起
- 调用初始化操作。
- 同时调用两个异步操作。
- 等待以上操作完成。
- 运行 加一动作。
- 完成初始化。
这是我期望的 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
实现了该流程,我知道这是 anti-pattern 并且它将在 1.0.0 版本中被删除所以我想知道我是如何做到的可以使用纯 epics
我的工作解决方案
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);
}
我也一直在尝试使用 forkEpic
从这个 comment 那样
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.done
和 asyncB.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_FINISHED
和 INITIALIZATION_FINISHED
的事情,因为问题中没有包含相关的代码,所以不确定它会做什么。
您可能会注意到这主要是一个常规的 RxJS 问题,其中项目流 碰巧 是动作。这真的很有帮助,因为当你寻求帮助时,如果你将问题设计为通用 RxJS,你可以从整个 RxJS 社区询问。
请注意,我在开始之前听完了;如果 done
在 started
之后同步发出,这通常是最佳实践。如果你不先听,你就会错过它。因为它是异步的所以没关系,但通常仍然是最佳实践并且在您进行单元测试时很有帮助。
我正在尝试编写我的 INITIALIZE
操作,它应该按以下方式将一些异步操作链接在一起
- 调用初始化操作。
- 同时调用两个异步操作。
- 等待以上操作完成。
- 运行 加一动作。
- 完成初始化。
这是我期望的 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
实现了该流程,我知道这是 anti-pattern 并且它将在 1.0.0 版本中被删除所以我想知道我是如何做到的可以使用纯 epics
我的工作解决方案
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);
}
我也一直在尝试使用 forkEpic
从这个 comment 那样
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.done
和 asyncB.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_FINISHED
和 INITIALIZATION_FINISHED
的事情,因为问题中没有包含相关的代码,所以不确定它会做什么。
您可能会注意到这主要是一个常规的 RxJS 问题,其中项目流 碰巧 是动作。这真的很有帮助,因为当你寻求帮助时,如果你将问题设计为通用 RxJS,你可以从整个 RxJS 社区询问。
请注意,我在开始之前听完了;如果 done
在 started
之后同步发出,这通常是最佳实践。如果你不先听,你就会错过它。因为它是异步的所以没关系,但通常仍然是最佳实践并且在您进行单元测试时很有帮助。