Как я могу связать несколько зависимых подписок, используя операторы и преобразования rxjs? - PullRequest
0 голосов
/ 24 мая 2019

У меня есть функция, которая должна извлекать данные из одного API, а затем использовать результат для получения данных из нескольких дополнительных API. Первое извлечение данных необходимо для всех из них, но некоторые из последующих вызовов могут выполняться параллельно, а другим требуются данные, возвращаемые одним или несколькими параллельными вызовами, прежде чем они смогут выполняться. В настоящий момент у меня есть часть этой работы, когда я делаю три подписки внутри другой подписки (это четыре подписки в одной функции для тех из вас, кто считает), но мне это пахнет неправильно, и все, что я прочитал, говорит, что это или анти-шаблон или просто неправильно. Мне нужен способ заставить все эти вещи работать в правильном порядке - там, где это необходимо, - и вернуть мои данные.

Я рассмотрел несколько опций rxjs и думаю, что мне нужно использовать некоторую комбинацию forkJoin (для элементов, которые могут работать параллельно) и mergeMap (для элементов, которые зависят от результатов forkJoin). Текущая установка заключается в том, чтобы сделать вызов моей службе и подписаться, затем в рамках этой подписки forkJoin и вызвать несколько других функций, подписаться на нее, и в рамках этого сделать еще два вызова и подписаться на дополнительные вызовы.

getThingFromService(id: number): any {
  const drinks = {};
  this.thingService.getThingById(id)
    .subscribe((thing) => {
      this.thing = thing;
      forkJoin([
        this.getTea(thing.tea.id),
        this.getCoffee(thing.coffee.id),
        this.getSoda(thing.soda.id)
      ])
      .subscribe((data) => {
        drinks.tea = data[0];
        drinks.coffee = data[1];
        drinks.soda = data[2];
        this.getCoffeeTypeById(drinks.coffee.bean.id)
          .subscribe((bean) => {
            drinks.coffeeBean = bean;
          })
        this.getSodaTypeById(drinks.soda.flavors.id)
          .subscribe((flavor) => {
            drinks.sodaFlavor = flavor;
          });
      });
    )}
}

getTea(id: number) {
  return this.thingService.getTea(id);
}

getCoffee(id: number) {
  return this.thingService.getCoffee(id);
}

getSoda(id: number) {
  return this.thingService.getSoda(id);
}

getCoffeeTypeById(id: number) {
  return this.otherService.getCoffee(id);
}

getSodaTypeById(id: number) {
  return this.yetAnotherService.getSoda(id);
}

Все в этом коде беспокоит меня. Во-первых, смущает чтение и не очень понятно. Далее это резко упрощенная версия. Фактическая функция составляет около 90 строк. Тогда это не работает на 100%. Я думаю, что getSodaTypeById разрешается после всего остального и поэтому недоступен, когда мне это нужно, поэтому в результате я регистрирую его как «undefined». Наконец, должен быть какой-то способ сделать все, что я хочу сделать, это ясно и с одной подпиской.

Существует плохой код, который работает, плохой код, который не работает, и плохой код, который работает. Я не могу решить, какой из них является худшим.

Редактировать: удалить «запись» и заменить на «вещь»

1 Ответ

2 голосов
/ 25 мая 2019

Некоторые вещи для рассмотрения.Попробуйте использовать оператор трубы.Если вам нужно создать побочные эффекты, нажмите.Для вложенных подписок попробуйте switchMap.Также вам могут не понадобиться дополнительные методы, которые просто возвращают услугу.

Вот быстрое возможное решение.Всего наилучшего.

Ссылка на пример https://stackblitz.com/edit/angular-rxjs-nested-subscriptions?file=src/app/app.component.ts

    this.thingService.getThingById(id).pipe(
      tap((thing) => {
        this.thing = thing;
      }),
      switchMap(_ => forkJoin([
        // NOTE: not sure where record comes from
        // if it is related to thing then it can be get passed down
        this.thingService.getTea(record.tea.id),
        this.thingService.getCoffee(record.coffee.id),
        this.thingService.getSoda(record.soda.id)
      ])),
      switchMap(([tea, coffee, soda]) => forkJoin([
        this.getCoffeeTypeById(coffee.bean.id),
        this.getSodaTypeById(soda.flavors.id)
      ]))).subscribe((data) => {
        drinks.coffeeBean = data[0];
        drinks.sodaFlavor = data[1];
      }
    );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...