取消基于有效负载而不是效果的可观察性

Exp*_*lls 6 observable rxjs typescript ngrx angular

我有一个服务,向后端发出http请求我无法控制获取营销页面内容.有时,我需要同时加载多个营销内容.我可以创建一个调用服务的效果.

@Effect()
marketingContent$ = this.actions$
  .ofType(LOAD_MARKETING_CONTENT)
  .switchMap(({ payload }) => this.marketingService.getContent(payload)
    .map(content => Action.LoadMarketingContentComplete(content))
  )
Run Code Online (Sandbox Code Playgroud)

这很好,我可以打电话store.dispatch(Action.LoadMarketingContent('A')).

问题是,如果我需要一次加载多个营销内容,.switchMap则会取消之前的请求.

store.dispatch(Action.LoadMarketingContent('A'));
store.dispatch(Action.LoadMarketingContent('B'));
// Only `'B'` is loaded since 'A' gets canceled before it completes
Run Code Online (Sandbox Code Playgroud)

我可以使用.mergeMap而不是.switchMap,但重复请求将不会被取消.

我还可以使用单独的操作来加载每个营销内容,但这需要为每个部分创建一个动作和效果.

有没有一种方法可以.switchMap用来取消对同一内容的请求(在哪里payload相同?)或同时在同一个流中取消重复请求时同时发出不同请求的方式?

car*_*ant 6

如果你介绍一个CANCEL_MARKETING_CONTENT动作,你可以做这样的事情mergeMap:

@Effect()
marketingContent$ = this.actions$
  .ofType(LOAD_MARKETING_CONTENT)
  .mergeMap(({ payload }) => this.marketingService
    .getContent(payload)
    .map(content => Action.LoadMarketingContentComplete(content))
    .takeUntil(this.actions$.ofType(CANCEL_MARKETING_CONTENT))
  );
Run Code Online (Sandbox Code Playgroud)

基本上,这将允许您加载任意数量的营销内容,但是您可以通过在发送CANCEL_MARKETING_CONTENT操作之前调度LOAD_MARKETING_CONTENT操作来取消任何挂起的加载.

例如,要仅加载片段A,您可以这样做:

store.dispatch(Action.CancelMarketingContent());
store.dispatch(Action.LoadMarketingContent('A'));
Run Code Online (Sandbox Code Playgroud)

并装载两件AB,你可以这样做:

store.dispatch(Action.CancelMarketingContent());
store.dispatch(Action.LoadMarketingContent('A'));
store.dispatch(Action.LoadMarketingContent('B'));
Run Code Online (Sandbox Code Playgroud)

实际上,有一种类似但更整洁的方式,它不涉及使用其他动作.

您可以使用与取消触发器相同的有效负载调度相同的操作.例如:

@Effect()
marketingContent$ = this.actions$
  .ofType(LOAD_MARKETING_CONTENT)
  .mergeMap(({ payload }) => this.marketingService
    .getContent(payload)
    .map(content => Action.LoadMarketingContentComplete(content))
    .takeUntil(this.actions$
      .ofType(LOAD_MARKETING_CONTENT)
      .skip(1)
      .filter(({ payload: next }) => next === payload)
    )
  );
Run Code Online (Sandbox Code Playgroud)

从内存中,skip将需要跳过当前由效果处理的动作.答案假定payload"A""B"等等.