为什么可观察源在race(或merge)中使用时不会发出值,但在我手动订阅它时会发出

时间:2018-01-15 00:39:16

标签: javascript angular rxjs

我的代码中有三个可观察的源,它们发出相同类型的值。

    const setTitle$ = params$.do(
        params => this.titleService.setTitle( `${params[1].appname} - ${this.pagename}` )
    ).switchMap(
        () => Observable.of(true)
    );

    const openDocument$ = params$.switchMap(
        params => this.openDocument(params[0].id)
    );

    const saveDocument$ = params$.switchMap(
        params => this.saveDocument(params[0].id)
    );

当我在这样的比赛中使用它们时

setTitle$.race(
    openDocument$,
    saveDocument$
).subscribe();

仅适用于setTitle,当我手动订阅另外两个喜欢

const openDocument$ = params$.switchMap(
    params => this.openDocument(params[0].id)
).subscribe();

const saveDocument$ = params$.switchMap(
    params => this.saveDocument(params[0].id)
).subscribe();
然后他们也工作了。帮助我理解为什么会这样,以及如何强制在种族,合并等方面工作所有来源。

2 个答案:

答案 0 :(得分:1)

documentation开始,.race()运算符执行此操作:

  

使用发出第一个的可观察对象。

这就是为什么你只能得到 ONE 发射,因为只有三个可观察到的发射器中的一个会被发射出来。

您要找的是.forkJoin().combineLatest()

如果您希望所有可观察对象并行执行并等待所有可观察对象作为一个可观察对象返回,请使用.forkJoin()

Observable
    .forkJoin([...setTitle$, openDocument$, saveDocument$])
    .subscribe(([setTitle, openDocument, saveDocument]) => {
        //do something with your your results.
        //all three observables must be completed. If any of it was not completed, the other 2 observables will wait for it
    })

如果您想要听取所有可观察物的每一次发射,无论它们被发射,请使用.combineLatest()

Observable
    .combineLatest(setTitle$, openDocument$, saveDocument$)
    .subscribe(([setTitle, openDocument, saveDocument]) => {
        //do something with your your results.
        // as long as any of the observables completed, it will be emitted here.
    });

答案 1 :(得分:0)

问题在于共享的params来源。

const params$ = this.route.params.map(
        routeParams => {

            return {
                id: <string>routeParams['id']
            };

        }
    ).combineLatest(
        this.config.getConfig()
    ).share();

我与分享运营商分享了它。但是从第一条评论到我的问题的这篇文章我发现了这个:

  

在具有默认值的流上使用多个异步管道时,.share()运算符可能会导致问题:

     

share()将在第一个订阅上发布流的第一个值。第一个异步管道将触发该订阅并获取该初始值。然而,第二个异步管道将在该值已经被发出之后订阅,因此错过了该值。

     

此问题的解决方案是.shareReplay(1)运算符,它将跟踪流的先前值。这样,所有异步管道都将获得最后一个值。

我将share()替换为shareReplay(1),所有来源都开始发布值。

const params$ = this.route.params.map(
        routeParams => {

            return {
                id: <string>routeParams['id']
            };

        }
    ).combineLatest(
        this.config.getConfig()
    ).shareReplay(1);

感谢大家的帮助!