RxJS:我应该如何通过socket.js事件更新observable中的元素?

时间:2018-02-15 16:39:30

标签: javascript angular rxjs rxjs5

试图重新实现公司的主要应用,从承诺和命令式风格转换为RxJS和功能风格。并发现自己处于特定的情况。

问题:我们在系统中有一个可以过滤的帖子列表。 所以,我创建了一个非常简单的过滤器组件和一个列表组件,我收到这样的数据:

this.items = this.filterChange
    .startWith(this.filterComponent.initialValue);
    .debounceTime(400)
    .switchMap((data) => this.process(data))
    .share();

但是我需要从套接字插入另一个事件来更新列表中的各个元素。我们的process函数可以理解这两个事件并对它们做出反应,但问题是:

merge(this.filterChange.debounceTime(400), this.socketUpdates)
    .startWith(this.filterComponent.initialValue);
    .switchMap((data) => this.process(data))
    .share();

如果在搜索更改后立即更新,我们会丢失搜索更改结果,在这种情况下该怎么办?

PS:我已经考虑选择combineLatest + pariwise来获得改变后的能力并做出反应。难道没有更优雅的解决方案吗?

2 个答案:

答案 0 :(得分:2)

这实际上是RxJS的常见错误,当您使用switchMap(或者concatMap)时,您正在使用mergeMap

switchMap对于非副作用的只读请求/消息非常安全。如果你是'尝试通过网络更新记录,并且您关心它的完成顺序和处理结果,您想要使用concatMap。如果您不关心结果的排序,则应使用mergeMap

  • switchMap - 在获得新值时取消订阅任何待处理的Observable,从而放弃其响应。
  • mergeMap - 将立即开始并运行它创建的所有Observable并完成,而不必关心结果在它们合并后返回的顺序。
  • concatMap - 按顺序一次只运行一个Observable,不删除任何内容。
merge(this.filterChange.debounceTime(400), this.socketUpdates)
    .startWith(this.filterComponent.initialValue);
    .concatMap((data) => this.process(data))
    .share();

答案 1 :(得分:0)

如果所需的行为是阻止从套接字进行任何更新,直到搜索输入被去抖动,那么您应该使一个流依赖于另一个,而不是合并。这可能是适用于您的用例的方法:

this.filterChange.switchMap( data => {
    return Observable.of( data )
           .debounceTime( 400 )
           .concat( this.socketUpdates );
  })
  .startWith(this.filterComponent.initialValue);
  .switchMap((data) => this.process(data))
  .share();

我不确切知道debounceTime运算符的用例是什么,如果您正在对文本输入或其他数据进行去抖动,但是您应该能够将其移出switchMap如果你愿意的话。上面的这个实现可能真的很可能" chatty"订阅socketUpdates流,这也可能对您产生影响。

this.filterChange.debounceTime( 400 ).switchMap( data => {
    return Observable.of( data ).concat( this.socketUpdates );
  })
  .startWith(this.filterComponent.initialValue);
  .switchMap((data) => this.process(data))
  .share();