Уведомить о завершении последовательности наблюдаемых объектов

Я пытаюсь использовать RxJS Observables для фильтрации списка объектов на основе выбора пользователей. Чтобы получить список отфильтрованных объектов, мне нужно последовательно вызвать три отдельные службы и передать значения из предыдущей службы в следующую службу.

ПРИМЕЧАНИЕ 1: Каждая из этих трех служб возвращает Observable

ЗАМЕТКА 2: Каждая служба может возвращать произвольное количество результатов, которые необходимо передать следующей службе.

Только после того, как третья служба завершит отправку всех своих значений, мой код может продолжаться нормально.

Вот что у меня есть прямо сейчас:

this.firstService.getFirstResults(filterOption)
            .subscribe(firstResult => this.secondService.getSecondResults(firstResult)
                .subscribe(secondResult => this.thirdService.getThirdResults(secondResult)
                    .subscribe(thirdResult => this.processResult(thirdResult, firstResult),
                    null,
                    () => console.info("COMPLETE")))
            );

Приведенный выше код работает у меня почти идеально. В конце концов, функция processResult() правильно строит массив со всеми отфильтрованными объектами.

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

ЗАМЕТКА 3: В последнем вызове processResult() мне нужно передать как значение thirdResult, так и соответствующее значение firstResult, возвращаемое из firstService.getFirstResults().

Используйте оператор switchMap (), mergeMap () или concatMap () (в зависимости от того, что вы действительно хотите). Как они могут работать параллельно, если вам нужно значение, испускаемое первым, для вызова второго?

JB Nizet 10.12.2018 22:55

Извините, параллель - плохой выбор. Думаю, я хотел сказать асинхронно. Только что отредактировал сообщение, чтобы исправить.

JDuffy 10.12.2018 22:59

Не могли бы вы предоставить фрагмент кода, показывающий, как я могу преобразовать приведенный выше код для использования switchMap или mergeMap? Я пробовал это сам, думая, что это решит мою проблему, но окончательный массив фильтров так и не был построен, и журнал консоли COMPLETE так и не был напечатан. При поиске примера кода в Интернете большинство из них демонстрируют последовательности функций, которые не принимают никаких параметров или не имеют статических параметров.

JDuffy 10.12.2018 23:27
gist.github.com/jnizet/aeb37e62a059c99f2bb43f19d0b82e4a. Но ваш наблюдаемый будет завершен только в том случае, если все наблюдаемые будут завершены (в случае mergeMap)
JB Nizet 10.12.2018 23:33

Спасибо за фрагмент, так как сейчас я, кажется, добился прогресса. Моя единственная оставшаяся проблема, похоже, заключается в том, что я по ошибке поместил переменную filterOption в качестве второго параметра функции processResult(), хотя на самом деле это должно быть значение, возвращаемое firstService, например, переменная processResult (thirdResult, firstResult) . Though with the new code setup, the firstResult не видна после вызова этой функции. Любые идеи?

JDuffy 11.12.2018 00:56
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
5
258
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

switchMap предоставил второй параметр для реструктуризации возвращаемого значения, ниже показано, как это сделать.

function getResult(filterOption) {
  return this.firstService.getFirstResult(filterOption).pipe(
    switchMap(
      firstResult => this.secondeService.getSecondResult(firstResult),
      ([firstResult, secondResult]) => ({ firstResult, secondResult }),
    ),
    switchMap(
      ({ secondResult }) => this.thirdService.getThirdResult(secondResult),
      ([{ firstResult }, thirdResult]) => ({ firstResult, thirdResult }),
    ),
  );
}

getResult(filterOption).subscribe({
  next: ({ firstResult, thirdResult }) => this.processResult(thirdResult, firstResult),
  completed: () => console.info('completed'),
});

Спасибо вам обоим. У меня теперь он правильно работает с оператором mergeMap. Пришлось объединить все это в одну функцию для целей определения объема, поскольку я использую TypeScript, а не JavaScript, но в остальном это, по сути, тот же код выше, который работал у меня.

JDuffy 16.12.2018 22:02

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