我有一个由效果调用的昂贵计算.我现在想要确保,这个计算永远不会被同时调用,即如果在第一次调用仍在运行时第二次调用它,则应忽略第二个调用.
我解决这个问题的方法是创建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
因此,昂贵的计算执行两次.
我怎么能阻止这个?
解决方法:
您可能会看到LOADING错误两次,因为Action.setLoading尚未执行.这很可能取决于调度和操作的同步/异步.最好不要对此做出假设.
一般来说,如果要限制同时执行的操作数/一次只执行一个操作,则可以在rxjs v4 / v5中使用多个运算符:
> flatMapWithMaxConcurrent | mergeMap
:将同时订阅参数化的最大可观察量,保留剩余可观察量的缓冲区以便订阅,并在插槽可用时订阅它们.因此没有损失.
> flatMapFirst
| exhaustMap:只会在给定时间订阅一个可观察量.在当前可观察的执行过程中出现的可观察性丢失了.当完成当前可观察量时,可以订阅新的可观察量.
> concatMap
:一次只能订阅一个观察者.将保留剩余可观察量的缓冲区以进行订阅,并且将在当前可观察量已完成时按顺序执行此操作.因此没有损失.
您还可以查看以下问题:Batching using RxJS?
总之,也许这样的事情对你有用:
@Effect()
calculate$= this.updates$
.whenAction(CALCULATE)
.exhaustMap(data => DO_THE_EXPENSIVE_CALCULATION())
;
我在这里假设DO_THE_EXPENSIVE_CALCULATION()返回一个promise(也可以是一个可观察的).