如何仅在另一部史诗结束时才发出史诗?

How to emit an epic only if another epic finished?

我有 2 个实体:收款人和交易。我有 payeeCreateEpic 过滤 started 发出 finished/failed 的常规链。 transactionCreateEpic.

也一样

为了简单起见,假设收款人只有 UUID 和姓名。然而,交易可以有 3 种可能性之一:未附加到任何收款人(有效负载有 payee: null),附加到现有收款人(在 UI 上,用户有一个所有收款人的下拉列表,他可以在其中选择一个,具有 payee: payee-uuid) 或附加到 现有收款人的有效载荷(在 UI 上,用户可以选择创建不保存到后端的收款人,但是如果保存了整个交易,则应该保存,在我发送的有效负载中 payee: payee-name).

现在,如果提交创建交易时没有收款人或现有收款人,我只需转到 POST /transactions 并等待它解决以发出 finishedfailed 操作transactionCreateEpic.

但是,如果 !isUuid(txPayload.payee) 的计算结果为真,在 transactionCreateEpic 的史诗中,我想用收款人姓名启动 payeeCreateEpic,并等待 finished =>然后从后端使用 payee-id 创建交易,或者 failed => 中止交易(并向用户显示错误)。

我不确定该怎么做,因为在事务史诗中,我已经在 TRANSACTION_CREATE_STARTED 操作的过滤器中,但不确定如何订阅 [=11] 发出的另一个操作=].

一些代码:

const createPayeeEpic = (actions$: Observable<Action>) =>
    actions$.pipe(
        filter(CreateAction.start.match),
        mergeMap((action) =>
            from(MoneyPinApiClient.getInstance().payee.create(CreateRequestAdapter(action.payload))).pipe(
                map((response) => CreateAction.success({
                    params: action.payload,
                    result: CreateResultAdapter(response.data)
                })),
                catchError((err) => of(
                    <any>CreateAction.failure({params: action.payload, error: err}),
                    <any>MoneyPinApiErrorAction(err)
                ))
            )
        )
    );
const createTransactionEpic = (actions$: Observable<Action>) =>
    actions$.pipe(
        filter(CreateAction.start.match),
        mergeMap((action) => {
            if(!isUuid(action.payload.payee) {
               **EMIT PayeeCreateAction.start({name: action.payload.payee})**
               **WAIT FOR PayeeCreateAction.success (or PayeeCreateAction.failure)**
               action.payload.payee = resultOf(PayeeCreateAction.success).id;
            }
            return from(MoneyPinApiClient.getInstance().transaction.create(CreateRequestAdapter(action.payload))).pipe(
                map((response) => CreateAction.success({
                        params: action.payload,
                        result: CreateResultAdapter(response.data)
                    })),
                catchError((err) => of(
                    <any>CreateAction.failure({params: action.payload, error: err}),
                    <any>MoneyPinApiErrorAction(err)
                ))
            )
        })
    );

看看 createTransactionEpic,这是我在实际启动 createPayeeEpic + 等待成功或失败时遇到困难的地方。

您的问题看起来像是线程同步问题。 使用一种线程同步模式。 例如。 https://en.wikipedia.org/wiki/Monitor_(synchronization)

解决方案是将事务的实际创建提取到某个工厂方法:

const transactionCreateStreamFactory = (action: MoneyPinAction<CreateActionParams>) =>
from(MoneyPinApiClient.getInstance().transaction.create(CreateRequestAdapter(action.payload))).pipe(
    concatMap((response) => CreateAction.success({
        params: action.payload,
        result: CreateResultAdapter(response.data)
    })),
    catchError((err) => of(
        <any>CreateAction.failure({params: action.payload, error: err}),
        <any>MoneyPinApiErrorAction(err)
    ))
);

然后创建交易史诗实际上是这样的:

const createTransactionEpic = (actions$: Observable<Action>) =>
actions$.pipe(
    filter(CreateAction.start.match),
    mergeMap((action) => {
        const {payee, payload} = action.payload;
        if (payee && payload.payee_id) {
            return merge(
                actions$.pipe(
                    filter(PayeeCreateAction.success.match),
                    filter((payeeResponse) => payeeResponse.payload.result.payee.id === payload.payee_id),
                    take(1),
                    mergeMap(() => transactionCreateStreamFactory(action)),
                ),
                actions$.pipe(
                    filter(PayeeCreateAction.failure.match),
                    filter((payeeResponse) => payeeResponse.payload.params.payload.id === payload.payee_id),
                    take(1),
                    map(() => CreateAction.failure({
                        params: action.payload,
                        error: new Error("failed to create payee")
                    }))
                )
            ).pipe(
                startWith(PayeeCreateAction.start({
                    notebook_id: action.payload.notebook_id,
                    payload: {id: payload.payee_id, name: payee}
                }))
            );
        } else {
            return transactionCreateStreamFactory(action);
        }
    })
);

因此,如果在创建过程中给出了带有 id 的收款人,我将启动另一个管道,该管道监听 payee.successpayee.failure 操作,过滤相关操作(以防多个操作这种类型可能会在并发创建或其他过程中出现),只侦听一次(take(1)),然后将其合并映射到实际的创建事务史诗,整个流从 payee.start 处理的操作开始收款人史诗(它会发出收款人操作的成功/失败)。