switchMap与角度http客户端保持/取消请求

时间:2019-08-10 07:40:16

标签: angular rxjs ngrx angular-httpclient ngrx-effects

我有一些类似ngrx的效果

effect1 = this.actions$.pipe(
 ofType('x'), 
 switchMap(data => this.httpClient.post(data)), 
 map(result => new mappedAction(result))
);

对于effect1,当接收到新的触发器时,我想忘记并取消之前的请求,将其取消。我读了一些有关它的内容,看来这还是httpClient请求上的switchMap所做的。

对于另一个effect2,我们假设,当收到新的触发器时,我不在乎上一个请求的结果,但是我在乎请求是否完成。我应该用什么代替switchMap?

3 个答案:

答案 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))
);

https://stackblitz.com/edit/rxjs-vu2gfp

答案 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)
       )
    )
 );

很抱歉缩进不正确,我希望它能正常工作,但实际上并未经过测试并在我的手机上编写。如果代码片段有任何问题,请告诉我,以后我可以对其进行改进。