Angular 9: подписка на forkJoin не работает

#javascript #angular #rxjs #observable #angular9

#javascript #angular #rxjs #наблюдаемый #angular9

Вопрос:

Я пытаюсь загрузить данные страницы в компоненте верхнего уровня в Angular 9, используя наблюдаемые (rxjs 6.5.1). Когда я подписываюсь на каждую из этих служб по отдельности, я вижу, что данные возвращаются просто отлично:

 ngOnInit(): void {
  const technicianSubscription = this.techniciansClientService.getByTechnicianId(this.technicianId).subscribe(technician => console.log(technician));
  const technicianReviewsSubscription = this.technicianReviewsClientService.getByTechnicianId(this.technicianId).subscribe(technicianReviews => console.log(technicianReviews));
}
  

Когда я пытаюсь использовать forkJoin, данные из метода subscribe никогда не возвращаются:

 ngOnInit(): void {
  this.pageDataSubscription = forkJoin({
    technician: this.techniciansClientService.getByTechnicianId(this.technicianId),
    technicianReviews: this.technicianReviewsClientService.getByTechnicianId(this.technicianId),
  }).subscribe(
    // data is never logged here
    data => console.log(data)
  );
}
  

Я пытался передать forkJoin массив служебных вызовов, а также пробовал использовать zip, но безрезультатно. Что здесь происходит?

Комментарии:

1. странно.. похоже, это должно сработать на самом деле

2. Оба вызова getByTechnicianId выполняются правильно? Проверьте сетевую консоль.

3. описываемое вами поведение может быть достигнуто, когда один из потоков или оба из них генерируют события, но не завершаются. forkJoin генерирует событие только тогда, когда все его источники завершены. не могли бы вы проверить эту версию?

4. @Andrey Я думаю, что это то, что происходит. Я попытался поместить другую службу в forkJoin, и это было успешно. Похоже, что вызов технической службы не завершается. Не могли бы вы предложить использовать combineLatest, подобный приведенному ниже ответу, для моей ситуации?

5. это зависит от ситуации, с которой вы пытаетесь справиться. не могли бы вы предоставить наблюдаемый результат, который возвращает техническая служба? Если это слишком сложно, я думаю, ..getById(...).pipe(take(1)) взятие всего 1 события из этого наблюдаемого решит проблему за вас

Ответ №1:

Я бы рекомендовал использовать combineLatest from rxjs . Его проще использовать

 import {combineLatest} from `rxjs`;

componentIsActive = true;
ngOnInit(): void {
  combineLatest([
    this.techniciansClientService.getByTechnicianId(this.technicianId),
    this.technicianReviewsClientService.getByTechnicianId(this.technicianId),
  ]).pipe(
    map(([technician, technicianReviews]) => ({technician, technicianReviews})),
    takeWhile(() => this.componentIsActive)
  ).subscribe(data => console.log(data));
}
  

Комментарии:

1. Это сработало! Все еще копаюсь в документах, чтобы узнать, что пошло не так с forkJoin…

2. это также подтверждает теорию, которую я предложил в комментарии к вопросу. вы должны изучить свою ситуацию и выбрать наилучший вариант

3. также вещь, которая была бы полезна и для @Owen — takeWhile способ отмены подписки хуже, чем takeUntill, поскольку он будет отменять подписку только тогда, когда событие проходит через этот поток. Это может привести к утечке памяти, если после уничтожения компонента не будет отправлено ни одного события. также это не отменит ненужные http-запросы, если компонент будет уничтожен до загрузки ответа

4. @Andrey спасибо, обычно я использую либо, в основном, takeUntil, но теперь я буду придерживаться takeUntil

5. @EJMorgan, у вас ошибка типа при использовании forkJoin, является forkJoin(this.techniciansClientService.getByTechnicianId(..),this.technicianReviewsClientService.getByTechnicianId(..).subscribe(([technician, technicianReviews])=>{...})