根据有效载荷而不是效果取消可观察

Posted

技术标签:

【中文标题】根据有效载荷而不是效果取消可观察【英文标题】:Cancel observable based on payload rather than effect 【发布时间】:2018-07-12 12:15:29 【问题描述】:

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

@Effect()
marketingContent$ = this.actions$
  .ofType(LOAD_MARKETING_CONTENT)
  .switchMap(( payload ) => this.marketingService.getContent(payload)
    .map(content => Action.LoadMarketingContentComplete(content))
  )

这很好,我可以打电话给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

我可以使用.mergeMap 代替.switchMap,但是重复的请求不会被取消。

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

有没有一种方法可以让我使用.switchMap 只取消对相同内容的请求(payload 是相同的?)或另一种方法在取消同一流中的重复请求的同时发出不同的请求?

【问题讨论】:

【参考方案1】:

您可以更改效果以分组检索营销内容,而不是专门取消效果,并且仍然利用switchMap取消后续请求。

@Effect()
marketingContent$ = this.actions$
  .ofType(LOAD_MARKETING_CONTENT)
  .switchMap(( payload ) => forkJoin(
    payload.map(name => this.marketingService.getContent(payload))
  ).map(content => Action.LoadMarketingContentComplete(content))

在这种情况下,payload 将是要检索的内容名称数组,而不是允许您将内容作为组加载的单个名称。

【讨论】:

【参考方案2】:

如果您引入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))
  );

基本上,这可以让您加载任意数量的营销内容,但您可以通过在发送 LOAD_MARKETING_CONTENT 操作之前发送 CANCEL_MARKETING_CONTENT 操作来取消任何待处理的加载.

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

store.dispatch(Action.CancelMarketingContent());
store.dispatch(Action.LoadMarketingContent('A'));

要同时加载AB,您可以这样做:

store.dispatch(Action.CancelMarketingContent());
store.dispatch(Action.LoadMarketingContent('A'));
store.dispatch(Action.LoadMarketingContent('B'));

实际上,有一种类似但更简洁的方法,它不涉及使用其他操作。

您可以使用具有相同负载的相同操作的调度作为取消触发器。例如:

@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)
    )
  );

根据记忆,需要skip 来跳过当前由效果处理的动作。并且答案假定payload"A""B" 等。

【讨论】:

很好的答案。根据我的测试,我认为不需要 skip(1)。 它给我错误 'Actions' 类型上不存在属性'ofType' 你能帮我解决这个错误,我需要在这里使用管道运算符吗?

以上是关于根据有效载荷而不是效果取消可观察的主要内容,如果未能解决你的问题,请参考以下文章

我们是不是需要取消订阅完成/错误输出的可观察对象?

Knockoutjs ,取消可观察更新

我试图取消订阅一个可观察的角度但我收到错误,例如取消订阅不存在

嵌套可观察订阅问题,无法取消订阅

如何根据最后一次观察而不是字母顺序对情节进行排序? [复制]

Xamarin Forms:如何通知我以前的视图模型而不是需要修改可观察集合?