Angular - несколько условных http-запросов - PullRequest
1 голос
/ 13 марта 2020

Я немного борюсь с тем, чтобы придумать хорошее решение для выполнения нескольких http-запросов на основе результатов каждого из них. До сих пор я работал хорошо с switchMap, пока это только 2 http-запроса. Однако я обнаружил, что мне нужно выполнить 3, и я не уверен, как это сделать с помощью switchMap или есть ли лучшее решение для этого.

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

Позвольте мне привести упрощенный пример того, что я получил так far:

getData(): Observable<number> {
  const $subject = new Subject<number>();

  // loadData() takes in an id to specify what data to load
  service.loadData(1).pipe(
    switchMap(response => {
      if(response.length === 0) {
        return service.loadData(2);
      }
      else {
        return of(response);
      }
    }),
  ).subscribe(result => {
    $subject.next(result);
    $subject.complete();
  });
  return $subject.asObservable();

Теперь это работает просто отлично, моя проблема в том, что вызов loadData (2) может также вернуть ответ с length = 0, и в этом случае мне нужно вызвать LoadData (3).

Я попытался добавить еще одну SwitchMap в SwitchMap, но, похоже, это не сработало должным образом. Поэтому мой вопрос: как я могу проверить длину ответа loadData (2), и если он равен 0, вернуть service.loadData (3)?

Любая помощь или советы приветствуются: )

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Один прямой и неприятный способ - подписаться на каждый звонок индивидуально и проверить его результат.

getData(): Observable<number> {
  const $subject = new Subject<number>();

  service.loadData(1).subscribe(
    loadOneResponse => {
      if(loadOneResponse.length === 0) {
        service.loadData(2).subscribe(
          loadTwoResponse => {
            if(loadOneResponse.length === 0) {
              service.loadData(3).subscribe(
                loadThreeResponse => {
                  $subject.next(loadThreeResponse);
                  $subject.complete();
                },
                loadThreeError => {
                }
              );
            } else {
              $subject.next(loadTwoResponse);
              $subject.complete();
            }
          },
          loadTwoError => {
          }
        );
      } else {
        $subject.next(loadOneResponse);
        $subject.complete();
      }
    },
    loadOneError => {
    }
  );

  return $subject.asObservable();
}
0 голосов
/ 14 марта 2020

Одним из возможных решений является использование from с pipe

и takeWhile -> concatMap -> filter -> tap операторами.

getData в службе получит массив номеров идентификаторов, чтобы попытаться получить данные за.

from будет выдавать каждый идентификатор из массива ids.

concatMap не подписывается на следующее наблюдаемое, пока не завершится предыдущий.

filter будет игнорировать пустые результаты.

takeWhile отменит весь поток один раз take становится false

  getData(ids: number[]): Observable<number[]> {
    let take = true;
    return from(ids).pipe(
      takeWhile(() => take),
      concatMap(id => this.getDataFromApi(id)),
      filter(result => result.length > 0),
      tap(() => take = false)
    );
  }

Пример использования в компоненте:

  handleGetData() {
    console.log("component: getData");
    const ids = [1, 2, 3, 4];
    this.dataService.getData(ids).subscribe(data => {
      console.log("got data: ", data);
    });
  }

Рабочая stackblitz

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...