Angular - Возможен ли последующий http-вызов, каков наилучший подход? - PullRequest
0 голосов
/ 06 марта 2020

У меня есть ситуация, когда я выполняю http-запрос для получения массива данных. Однако в некоторых случаях возвращаемый результат - пустой массив, и если это так, мне нужно выполнить еще один запрос get.

позвольте мне проиллюстрировать на примере кода

let name;

ngOnInit() {
  this.service.getData().subscribe(response => {
    let data = response;
    if (data.length === 0) {
      this.service.getOtherData().subscribe(otherResponse => {
        data = otherResponse;
      });
    }
    this.name = data[0].name;
  });
}

Я попытался проиллюстрировать мою текущую дилемму: мне нужно свойство "name" первой записи в массиве. Однако, если результатом первого запроса является пустой массив, мне придется выполнить последующий вызов другого метода http.

Если первый запрос возвращает пустой массив, функция все равно попытается назначить свойство "name" первой записи в массиве, но так как оно не существует, я получаю невозможное чтение "name" из undefined, даже до того, как будет выполнен второй http-вызов. Если первый ответ - пустой массив, я бы хотел, чтобы остальная часть функции «ждала» при запуске, пока не получит ответ от второго http-вызова.

Каков правильный подход в этой ситуации? Я посмотрел на mergeMap / switchMap, но он не показался мне правильным выбором, поскольку мне не всегда нужно выполнять несколько запросов.

Любой совет очень важен!

Ответы [ 2 ]

2 голосов
/ 06 марта 2020

Я бы использовал switchMap в этой ситуации.

Попробуйте:

import { of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
....

name: any; // btw, not let name but just name 

ngOnInit() {
  this.service.getData().pipe(
   switchMap(response => {
     // if the length is 0, switch to the new HTTP method
     if (response.length === 0) {
       return this.service.getOtherData();
     } else {
     // if there is a length, keep this response
       return of(response);
     }
   }),
  ).subscribe(data => this.name = data[0].name);
}
0 голосов
/ 06 марта 2020

Почему бы не преобразовать их в Promises и не дождаться, чтобы они стали чище?

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

let name;

async ngOnInit(): Promise<void> {
  const response = await this.service.getData().toPromise();
  if (Array.isArray(response) && response.length > 0) {
    const otherResponse = await this.service.getOtherData().toPromise();
    name = otherResponse[0].name;
  } else {
    name = response[0].name;
  }
}

// Or, better yet. Return the name:

async ngOnInit(): Promise<string> {
  const response = await this.service.getData().toPromise();
  if (Array.isArray(response) && response.length > 0) {
    const otherResponse = await this.service.getOtherData().toPromise();
    return otherResponse[0].name;
  }
  return response[0].name;
}

// Invoking ngOnInit directly is a little awkward,
// but you can. I'm not sure where you're putting
// name, but it needs to be somewhere, obviously.
name = await ngOnInit();

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

https://www.learnrxjs.io/learn-rxjs/operators/transformation/exhaustmap

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