我有一些类似ngrx的效果
effect1 = this.actions$.pipe(
ofType('x'),
switchMap(data => this.httpClient.post(data)),
map(result => new mappedAction(result))
);
对于effect1,当接收到新的触发器时,我想忘记并取消之前的请求,将其取消。我读了一些有关它的内容,看来这还是httpClient请求上的switchMap所做的。
对于另一个effect2,我们假设,当收到新的触发器时,我不在乎上一个请求的结果,但是我在乎请求是否完成。我应该用什么代替switchMap?
答案 0 :(得分:3)
在这种情况下,您应该使用mergeMap
:
effect2 = this.actions$.pipe(
ofType('x'),
// inner subscription is not completed on source emition (many subscriptions allowed)
// but the order in which they complete is not mantained
mergeMap(data => this.httpClient.post(data)),
map(result => new mappedAction(result))
);
如果您认为顺序很重要,则应使用concatMap
。
答案 1 :(得分:2)
您可以实现一个自定义运算符,其作用类似于mergeMap
,但只发出您映射到的最后一个Observable的项。
function mergeMapLast<T, R>(next: ((data: T) => Observable<R>)): OperatorFunction<T, R> {
return (source: Observable<T>) => defer(() => {
let curr = 0;
return source.pipe(
mergeMap((data, index) => {
curr = index;
return next(data).pipe(filter(_ => index === curr));
})
);
});
}
用法
effect2 = this.actions$.pipe(
ofType('x'),
mergeMapLast(data => this.httpClient.post(data)),
map(result => new mappedAction(result))
);
答案 2 :(得分:1)
请注意使用switchMap
进行服务器端更改。实际上,由于发布请求,似乎您正在对某些资源进行服务器端更改。您需要确保,即使客户端取消了请求,后端仍然可以处理该请求。
从我的角度来看,对于effect2,您有2个选择。
ConcatMap
ConcatMap将触发器作为输入参数,并将执行您的http请求。如果在http请求仍在进行时有新的触发器,则该触发器将被缓冲,直到内部可观察(http)完成。根据您的情况,这可能会导致内存溢出。例如,请求需要10秒才能完成,但是每100毫秒触发一次此效果。所有这些触发器将被缓存并顺序执行。
MergeMap
MergeMap不会缓存触发器。动作触发后,它只是订阅内部可观察对象。但是,内部可观察对象可能会花费不同的时间,例如第一个http请求花费20秒,第二个http请求仅花费1秒。在这种情况下,第二个http请求的操作员链中的其他步骤将在第一个http请求完成之前执行。如果执行顺序对您很重要,那么这可能是个问题。
请注意,所有这些运算符都会发出http响应作为结果。如果您希望在http请求完成后转发触发值,可以使用类似的方法
this.action().pipe(
concatMap(x =>
forkJoin([of(x), this.http(...)]).pipe(
map(([x]) => x)
)
)
);
很抱歉缩进不正确,我希望它能正常工作,但实际上并未经过测试并在我的手机上编写。如果代码片段有任何问题,请告诉我,以后我可以对其进行改进。