Rxjs 如何在另一个流发出时动态更改流间隔

Rxjs 如何在另一个流发出时动态更改流间隔,rxjs,Rxjs,所以我有一个由字符串数组组成的流 const msgs = ['Searching...', 'Gathering the Data...', 'Loading the Dashboard...']; const msgs$ = Observable.from(msgs); 我需要每3秒钟按顺序发出其中一条消息,直到dataFetched$stream发出为止,这基本上意味着所有数据都到达页面。我不能在它们之间循环。一旦看到最后一条消息但数据尚未到达,它就不应该更改 我可以使用RxJS-zip

所以我有一个由字符串数组组成的流

const msgs = ['Searching...', 'Gathering the Data...', 'Loading the Dashboard...'];
const msgs$ = Observable.from(msgs);
我需要每3秒钟按顺序发出其中一条消息,直到
dataFetched$
stream发出为止,这基本上意味着所有数据都到达页面。我不能在它们之间循环。一旦看到最后一条消息但数据尚未到达,它就不应该更改

我可以使用
RxJS-zip
函数查看
msgs
中的每个字符串

const longInt$: Observable<number> = Observable.interval(3000);
const longMsgsOverTime$ = Observable.zip(msgs$, longInt$, msg => msg);
并继续显示加载消息,直到最后一条消息可见。每条消息只应显示一次

这对我来说是相当令人费解的——我可以勾选一些要求,但不能让它完全工作。 经过多次尝试,我得出结论,我们需要将
msgs
数组包装在一个主题中,以防止在我们从
longInt$
切换到
shortInt$
后再次循环使用所有这些数组

============================编辑===================== 以下是ggradnig的答案和代码,我编造了这个丑陋的东西(为了调试):

下面是我的chrome控制台的截图,看看会发生什么。
shortInt$
流将记录绿色消息,因为您可以看到它从未发生过,即使
dataFetched$
流发出(橙色虚线边框)。 在“fetch data emit”日志下面,我们应该看到绿色的背景消息,表示shortInt$流正在发射值

第二次编辑========================

下面是可观察到的
dataFetched$

fetchData(){
    console.log('%c fetching now', 'border: 2px dashed purple');

    // this.initLoader();

    this.dataFetched$ = Observable.combineLatest([
        this.heroTableService.getHeroTableData([SubAggs.allNetworks.key], AggFieldsMap.legends.name),
        this.researchService.benchmark(this.getSubAggsForOverviewTbl()),
        this.multiLineChartService.getEngagementOverTime(this.getSubAggsForNetworkEngagementsOverTimeTable())
    ]).pipe(
        share(),
        delay(7000),
        tap(v => {
            console.log('%c fetch data emit', 'border: 2px dashed orange', v);
        })
    );


    const sub = this.dataFetched$.subscribe(([heroTableRes, benchmarkRes, netByEngRes]: [ITable[], IBenchmarkResponse, any]) => {
         // this.loading = false; ==> moved to dashboard

         //xavtodo: split this shit into .do() or .tap under each http request call
         //hero table logic here
         this.heroTableData = heroTableRes;

         //////////////////////////////////////////////////////
         //engagement-by-network-table
         this.engagementByNetworkData = this.researchService.extractDataForEngagementByNetworkTable(benchmarkRes, this.getSubAggsForOverviewTbl());

         //////////////////////////////////////////////////////
         //network eng over time logic here MULTI LINE CHART
         this.engagementMultiLineData = this.multiLineChartService.extractEngagementData(netByEngRes, this.getSubAggsForNetworkEngagementsOverTimeTable());
         this.networks = this.multiLineChartService.getNetworks();
         this.multilineChartEngagements = Util.getNetworksWithAltNames(this.networks);
         this.publishedContentData = this.multiLineChartService.extractPublishedData(netByEngRes);

         //combined multiline chart
         this.multiLineChartData = {
             publishedData: this.publishedContentData,
             engagementData: this.engagementMultiLineData
         };
     });

    this.addSubscription(sub);
}

听起来像是
takeUntil
concat
的任务

第一个可见值是
longInt$
。它在
dataFetched$
发出后立即完成。对于此要求,您可以使用
takeUntil
。它将另一个可观测值作为参数,一旦该可观测值发出,源可观测值将完成

从文档中:

发出源可观察对象发出的值,直到
通知程序
可观察对象发出值为止

因此,第一步是:

const longInt$: Observable<number> = Observable.interval(3000)
    .pipe(takeUntil(dataFetched$));
注意:如果您使用的是RxJS 5或更低版本,请使用相应的运算符替换管道(..)语句。例如,
.pipe(concat(…)
变成
.concat(…)


这里有一个关于StackBlitz的例子:

我遵循了你的建议,但我从未输入shortInt$流。数据到达,但消息使用longInt$继续循环。我的代码在这里,这是由于您如何使用
zip
->在您的回答中,您使用longInt$压缩了3个值的可观测值(字符串数组),concent$与shortInt$合并,但可观测间隔永远不会发出
complete
,因此,concat函数永远不会执行。嗯。。longInt$应该在
takeUntil
通知发出时完成。我在我的帖子中添加了一个StackBlitz示例,您可以查看:)谢谢您的帮助。我仍然无法让它在我的应用程序中运行,即使是完全按照你的例子。当我进入它的流时,我只看到了
longInt$
排放物。
fetchData(){
    console.log('%c fetching now', 'border: 2px dashed purple');

    // this.initLoader();

    this.dataFetched$ = Observable.combineLatest([
        this.heroTableService.getHeroTableData([SubAggs.allNetworks.key], AggFieldsMap.legends.name),
        this.researchService.benchmark(this.getSubAggsForOverviewTbl()),
        this.multiLineChartService.getEngagementOverTime(this.getSubAggsForNetworkEngagementsOverTimeTable())
    ]).pipe(
        share(),
        delay(7000),
        tap(v => {
            console.log('%c fetch data emit', 'border: 2px dashed orange', v);
        })
    );


    const sub = this.dataFetched$.subscribe(([heroTableRes, benchmarkRes, netByEngRes]: [ITable[], IBenchmarkResponse, any]) => {
         // this.loading = false; ==> moved to dashboard

         //xavtodo: split this shit into .do() or .tap under each http request call
         //hero table logic here
         this.heroTableData = heroTableRes;

         //////////////////////////////////////////////////////
         //engagement-by-network-table
         this.engagementByNetworkData = this.researchService.extractDataForEngagementByNetworkTable(benchmarkRes, this.getSubAggsForOverviewTbl());

         //////////////////////////////////////////////////////
         //network eng over time logic here MULTI LINE CHART
         this.engagementMultiLineData = this.multiLineChartService.extractEngagementData(netByEngRes, this.getSubAggsForNetworkEngagementsOverTimeTable());
         this.networks = this.multiLineChartService.getNetworks();
         this.multilineChartEngagements = Util.getNetworksWithAltNames(this.networks);
         this.publishedContentData = this.multiLineChartService.extractPublishedData(netByEngRes);

         //combined multiline chart
         this.multiLineChartData = {
             publishedData: this.publishedContentData,
             engagementData: this.engagementMultiLineData
         };
     });

    this.addSubscription(sub);
}
const longInt$: Observable<number> = Observable.interval(3000)
    .pipe(takeUntil(dataFetched$));
const longMsgsOverTime$ = Observable.zip(msgs$, 
    longInt$.pipe(concat(shortInt$)), msg => msg);