如何防止并发效果执行

hig*_*ile 4 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));
    }
  });
Run Code Online (Sandbox Code Playgroud)

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

store.dispatch(Actions.calculate());
store.dispatch(Actions.calculate());
Run Code Online (Sandbox Code Playgroud)

输出是

LOADING false
LOADING false
Run Code Online (Sandbox Code Playgroud)

因此,昂贵的计算执行两次.我怎么能阻止这个?

use*_*222 6

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

一般来说,如果要限制同时执行的操作数/一次只执行一个操作,则可以在rxjs v4/v5中使用多个运算符:

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

  2. flatMapFirst| exhaustMap:只会在给定时间订阅一个observable.在当前可观察的执行过程中出现的可观察性丢失了.当完成当前可观察量时,可以订阅新的可观察量.

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

您还可以查看以下问题:使用RxJS进行批处理?

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

@Effect()
calculate$ = this.updates$
  .whenAction(CALCULATE)
  .exhaustMap(data => DO_THE_EXPENSIVE_CALCULATION())
  ;
Run Code Online (Sandbox Code Playgroud)

我在这里假设DO_THE_EXPENSIVE_CALCULATION()返回一个promise(也可以是一个可观察的).