如何防止并发效果执行

时间:2016-09-22 09:47:25

标签: javascript rxjs ngrx

我有一个由效果调用的昂贵计算。我现在想确保,这个计算永远不会被同时调用,即如果在第一次调用仍在运行时第二次调用它,则应忽略第二次调用。

我解决这个问题的方法是创建2个动作:calculate和setLoading。

@Effect()
calculate$ = this.updates$
  .whenAction(CALCULATE)
  .flatMap(data => {
    console.debug('LOADING', data.state.loading);
    if (!data.state.loading) {
      this.store.dispatch(Actions.setLoading(true));
      await DO_THE_EXPENSIVE_CALCULATION();
      this.store.dispatch(Actions.setLoading(false));
    }
  });

使用Actions.setLoading显然设置了state.loading。但是,如果我连续开始计算2次:

store.dispatch(Actions.calculate());
store.dispatch(Actions.calculate());

输出

LOADING false
LOADING false

因此,昂贵的计算执行两次。 我该如何防止这种情况?

1 个答案:

答案 0 :(得分:6)

您可能会看到Action.setLoading两次,因为flatMapWithMaxConcurrent尚未执行。这很可能取决于调度和操作的同步/异步。最好不要对此做出假设。

一般来说,如果你想限制同时执行的一些操作/一次只执行一个操作,你可以在rxjs v4 / v5中使用许多操作符:

  1. exhaustMap | mergeMap:将同时订阅参数化的最大可观察量,保留剩余可观察量的缓冲区以进行订阅,并在插槽可用时订阅它们。因此没有损失。

  2. flatMapFirst | @Effect() calculate$ = this.updates$ .whenAction(CALCULATE) .exhaustMap(data => DO_THE_EXPENSIVE_CALCULATION()) ; :只会在给定时间订阅一个observable。在当前可观察的执行过程中出现的可观察性丢失了。当完成当前可观察量时,可以订阅新的可观察量。

  3. concatMap:一次只能订阅一个observable。将保留剩余可观察量的缓冲区以进行订阅,并且将在当前可观察量已完成时按顺序执行此操作。因此没有损失。

  4. 您还可以查看以下问题:Batching using RxJS?

    总之,也许这样的事情对你有用:

    DO_THE_EXPENSIVE_CALCULATION()

    我在这里假设customer/account/create返回一个承诺(也可以是一个可观察的承诺)。