如何在angular2中同时订阅多个observable并等待,如果每个都有新的数据?

时间:2016-12-09 12:20:05

标签: angular typescript rxjs reactive-programming observable

我有一个角度组件,它使用3个服务。每个服务都有一个观察者,我可以订阅。如果通过websockets(feathers.js)发生观察到的更改,则必须更新组件的视图。 我想在ngInit上只调用doSomethingWithTheNewDataThatIsShownOnView()一次,我想,我可以用forkJoin做到这一点:

private ngOnInit(): void {
    Observable.forkJoin(
        this.filesService.inputs$,
        this.filesService.outputs$,
        this.processesService.items$
    ).subscribe(
        data => {
          this.inputs = data[0];
          this.outputs = data[1];
          this.processes = data[2];
          this.doSomethingWithTheNewDataThatIsShownOnView();
          this.ref.markForCheck();
        },
        err => console.error(err)
    );

    this.filesService.find();
    this.processesService.find();
}

按预期工作,但如果输入$ Observable或输出$ Observable有新数据,则不会再次调用subscribe。如果所有三个Observable都有新数据,则仅调用它。是否存在类似"如果所有三个可观测数据都有新数据,则等待100毫秒的间隔,如果不使用所有可观察数据的新数据,那么到目前为止还有新数据?"

我希望你明白,我想做什么:D

迎接

克里斯

1 个答案:

答案 0 :(得分:14)

combineLatest()应该这样做:

private ngOnInit(): void {
    Observable.combineLatest(
        this.filesService.inputs$,
        this.filesService.outputs$,
        this.processesService.items$
    ).subscribe(
        data => {
          this.inputs = data[0];
          this.outputs = data[1];
          this.processes = data[2];
          this.doSomethingWithTheNewDataThatIsShownOnView();
          this.ref.markForCheck();
        },
        err => console.error(err)
    );

    this.filesService.find();
    this.processesService.find();
}

您的代码的其他提示:

作为替代方案combineLatest()也采用可选的聚合方法,也作为旁注:尝试仅使用纯函数并避免使用有状态组件(this.inputsthis.outputs等..)并在模板中使用| async管道并尝试避免订阅中的太多逻辑,如果可能的话,尽量避免手动订阅,因为那些必须手动取消订阅但async -pipe可以自动为您处理:

autoUpdatedViewData$ = Observable.combineLatest(
        this.filesService.inputs$,
        this.filesService.outputs$,
        this.processesService.items$,
        (inputs, outputs, items) => ({inputs, outputs, items})
    )
    .map(({inputs, outputs, items}) => {
        return this.doSomethingWithTheNewDataThatIsShownOnView(inputs, outputs, items);
    });

private ngOnInit(): void {
    this.filesService.find();
    this.processesService.find();
}

// in your template
<div>{{autoUpdatedViewData$ | async}}</div>