RxJS concatMap подписка вызывается для второго Observable отдельно

Я пишу приложение Angular 6. Я ожидаю, что при изменении маршрута будет отображаться анимация загрузки, а также ожидающие запросы http. Так что у меня 2 Observables выглядят так. Для httpPendingRequests я реализую с помощью счетчика, написанного в HttpInterceptor Angular; и для locationChanged я подписался на события NavigationStart/NavigationEnd маршрутизатора.

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

И я использую concatMap для подписки на эти 2 Observables, код выглядит так:

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);
});

Поэтому я ожидаю, что это будет регистрировать "isloading" в консоли только при изменении местоположения, а также при наличии каких-либо ожидающих запросов. Это работает в этом сценарии. Однако я обнаружил, что он также регистрирует сообщение "isloading", когда есть только ожидающие http запросы, но местоположение не меняется. Это меня смутило, я думал, что оператор следит за тем, чтобы Наблюдаемые подписывались по порядку? Если первый (изменение местоположения) не излучает, то второй (ожидающий запрос) не должен запускаться? Я неправильно понимаю эту концепцию?

Кроме того... Я также попробовал другие методы для объединения Observables, zip, forkJoin, combLatest - все они только инициировали подписку в моем случае, поэтому я также не очень уверен, что было не так.

Я рад предоставить больше информации, если это необходимо. заранее спасибо

2 ответа

Вы можете взглянуть на тот факт, что вы используете BehaviorSubject,

BehaviorSubject требует всегда значение для излучения во время создания. Это означает, что locationChanged всегда выдает хотя бы одно уведомление.

Если вы предпочитаете использовать Subject Вы можете контролировать, когда отправляется первое уведомление.

В следующем примере, взятом непосредственно из вашего кода, вы не видите ничего зарегистрированного, так как 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);

Можно решить с помощью combineLatest наблюдаемый и map оператор. Вот демоверсия: https://stackblitz.com/edit/so-rxjs-concat.

Код находится в app.component.ts, Заглянуть в console.log значение, чтобы понять больше.

Другие вопросы по тегам