简体   繁体   English

分别调用RxJS concatMap订阅进行第二次Observable

[英]RxJS concatMap subscription is called for second Observable separately

I am writing an Angular 6 app. 我正在编写Angular 6应用。 I expect it to show a loading animation when route changes as well as there is also any pending http requests. 我希望它在路由更改以及有任何未决的http请求时显示加载动画。 So I have 2 Observables look like this. 所以我有2个Observables看起来像这样。 For httpPendingRequests, I am implementing with a counter written in Angular's HttpInterceptor; 对于httpPendingRequests,我使用Angular的HttpInterceptor编写的计数器来实现; and for locationChanged, I have subscribed to Router's NavigationStart/NavigationEnd events. 对于locationChanged,我已经订阅了Router的NavigationStart / NavigationEnd事件。

httpPendingRequests: BehaviorSubject<number>;
locationChanged: BehaviorSubject<boolean>;

And I am using concatMap to subscribe to these 2 Observables, code looks like this: 我正在使用concatMap订阅这两个Observable,代码如下所示:

this.locationChanged.pipe(
  concatMap(changed => {
    console.log('location change:' + changed);
    if (changed) {
      return this.httpPendingRequests;
    } else {
      return of(0);
    }
  }),      
  map(count => count > 0)
).subscribe(val => { 
  console.log('isloading: ' + val);
});

So I expect this to log 'isloading' to console only when location has been changed, plus if there is any pending requests. 因此,我希望只有在更改位置以及有任何待处理的请求时,此命令才能将“正在加载”日志记录到控制台。 It does work in this scenario. 在这种情况下它确实起作用。 However I found it also logs 'isloading' message when there is only pending http requests but location does not change. 但是,我发现当只有待处理的http请求但位置未更改时,它还会记录“正在加载”消息。 It made me confused, I thought the operator is making sure the Observables are subscribed in order? 这让我感到困惑,我以为操作员正在确保可观察变量的订购顺序? If the first one(location change) does not emit, then the second one(pending request) should not be triggered? 如果第一个(位置更改)没有发出,那么第二个(待处理的请求)不应该被触发? Am I understanding this concept wrong? 我是否理解这个概念错误?

Besides.. I have also tried other methods to combine Observables, zip, forkJoin, combineLatest - they all only triggered the subscription once in my case so I am also not very sure what was wrong. 此外..我还尝试了其他方法来组合Observables,zip,forkJoin,combinateLatest-在我的情况下,它们都仅触发一次订阅,因此我也不太确定出了什么问题。

I am glad to provide more informations if needed. 如果需要,我很高兴提供更多信息。 Thanks in advance 提前致谢

Can be solve by using combineLatest observable and map operator. 可以通过使用combineLatestmap运算符来解决。 Here is the demo: https://stackblitz.com/edit/so-rxjs-concat . 这是演示: https : //stackblitz.com/edit/so-rxjs-concat

Code is in app.component.ts . 代码在app.component.ts Take a look into console.log value to understand more. 查看console.log值以了解更多信息。

You may want to take a look at the fact that you are using BehaviorSubject . 您可能想看看您正在使用BehaviorSubject的事实。

BehaviorSubject requires always a value to emit at creation time. BehaviorSubject始终需要一个在创建时发出的值。 This means that locationChanged always emits at least one notification. 这意味着locationChanged总是发出至少一个通知。

If you rather use Subject you can control when the first notification is emitted. 如果您更喜欢使用“ Subject ,则可以控制何时发出第一个通知。

In the following example, taken directly from you code, you do not see anything logged since locationChanged never emits. 在下面的示例中,直接从您的代码获取,您不会看到任何记录,因为locationChanged从不发出。

const httpPendingRequests = new BehaviorSubject<number>(0);
const locationChanged = new Subject<boolean>();

locationChanged.pipe(
    concatMap(changed => {
      console.log('location change:' + changed);
      if (changed) {
        return httpPendingRequests;
      } else {
        return of(0);
      }
    }),      
    map(count => count > 0)
  ).subscribe(val => { 
    console.log('isloading: ' + val);
});

setTimeout(() => {
    httpPendingRequests.next(1);
}, 100);
setTimeout(() => {
    httpPendingRequests.next(2);
}, 200);
setTimeout(() => {
    httpPendingRequests.next(3);
}, 300);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM