Как реализовать несколько вложенных и взаимозависимых подписок с помощью операторов RxJS?

#angular #typescript #rxjs #observable #rxjs6

#angular #typescript #rxjs #наблюдаемый #rxjs6

Вопрос:

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

У меня есть 3 подписки, которые зависят друг от друга и запускают новую наблюдаемую в циклах forEach для каждого значения текущего цикла. Чтобы проиллюстрировать это более подробно, вот мой пример кода:

 this.subscriptionOne = this.serviceOne.getStreets().subscribe((streets) => {
  streets.forEach((street) => {
    this.subscriptionTwo = this.serviceTwo.getMetaData(street.id).subscribe((metaDatas) => {
      metaDatas.forEach((md) => {
        // do some stuff and then trigger another observable..
        this.subscriptionThree = this.serviceTwo.getStuff(md.id, md.type, md.name).subscribe((stuff) => {
          // do some other stuff
        });
      });
    });
  });
});
 

Как я могу избавиться от этой вложенности с помощью RxJS?

Ответ №1:

 let sub = this.serviceOne
  .getStreets()
  .pipe(
    mergeMap(streets => {
      return from(streets);
    }),
    mergeMap(street => {
      return this.serviceTwo.getMetaData(street.id);
    }),
    mergeMap(metaDatas => {
      return from(metaDatas);
    }),
    mergeMap(md => {
      return this.serviceTwo.getStuff(md.id, md.type, md.name);
    }),
    map(stuff => {
      // do your stuff
    })
  )
  .subscribe();
 

metaDatas доступно в последних двух операторах:

 let sub = this.serviceOne
  .getStreets()
  .pipe(
    mergeMap(streets => {
      return from(streets);
    }),
    mergeMap(street => {
      return this.serviceTwo.getMetaData(street.id);
    }),
    mergeMap(metaDatas => {
      return from(metaDatas).pipe(
        mergeMap(md => {
          return this.serviceTwo.getStuff(md.id, md.type, md.name);
        }),
        map(stuff => {
          // do your stuff
        })
      );
    })
  )
  .subscribe();
 

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

1. Значит, больше не нужно шлифовать foreach? Тогда, вероятно, это моя ошибка.. Позже я протестирую ваш подход и дам вам отзыв. Спасибо!

2. Да, вам больше не нужно forEach .

3. Есть ли также способ объединить последние две карты слияния или я все еще могу получить доступ / выполнить итерацию по «метаданным» в функции подписки? Потому что после вызова GetStuff() в последней карте слияния мне все еще нужны некоторые свойства из «метаданных» для генерации параметров для конечного объекта.

4. Вы можете сохранить metaDatas в переменной, которая принадлежит методу, содержащему всю подписку, или, конечно, вы можете заключить последние два оператора в родительский оператор.

5. Если вы хотите развернуть массивы, например streets , вы должны превратить их в наблюдаемые с from(streets) помощью или вы можете просто вернуть массив и mergeMap переиздать каждый элемент отдельно mergeMap(streets => streets) (ну, или использовать mergeAll вместо этого).