Несколько вызовов API с одним и тем же запросом - PullRequest
0 голосов
/ 07 апреля 2020

Я хочу сделать несколько HTTP-вызовов с одной и той же конечной точкой, передавая разные идентификаторы. Есть ли лучший способ справиться с этим из пользовательского интерфейса. Мы не можем изменить бэкэнд прямо сейчас, есть ли лучший способ?

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  loadedCharacter: {};
  constructor(private http: HttpClient) {}

  ngOnInit() {
    let character1 = this.http.get('https://swapi.co/api/people/1');
    let character2 = this.http.get('http://swapi.co/api/people/2');

    forkJoin([character, character2]).subscribe(results => {
      // results[0] is our character
      // results[1] is our character2
    });
  }
}

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

По сути, есть 2 варианта:

  1. Это вариант, который вы используете, где вы используете forkJoin() для объединения всех наблюдаемых в массив

    • PROS: вы знаете, что все ваши данные будут загружены в вас subscribe()
    • CONS: вам придется ждать каждый HTTP-запрос к fini sh до того, как forkJoin выдаст значение
      • Примечание: вы можете реализовать хорошую вспомогательную функцию, такую ​​как рекомендуется @Prince
  2. Вы можете использовать mergeMap() для своих идентификаторов и реагировать всякий раз, когда один наблюдаемых завершает

    • PROS: вам не нужно ждать каждого HTTP-запроса для завершения. Вы можете реагировать , когда они завершат . Кроме того, вы можете легче обрабатывать ошибки (поэтому, если один запрос не будет выполнен, вы все равно сможете продолжить работу с другими запросами).
    • CONS: Вы должны обрабатывать свои значения в .subscribe() немного по-другому

В конце дня Вам нужно будет решить, какой подход лучше для вас. В вашей реализации нет ничего плохого. Я заметил, что вы сохраняете ваш loadedCharacter как объект, поэтому, честно говоря, вариант 2 может подойти для вашего варианта использования

Пример кода для Вариант 2 . Посмотрите это stackblitz для небольшой демонстрации:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, from, Subject } from 'rxjs';
import { mergeMap, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  private endSubs$ = new Subject();
  loadedCharacter: {};
  constructor(private http: HttpClient) {}

  ngOnInit() {
    /* ids of all the characters you want to load*/
    const characterIds = [1, 2];

    /* this will emit each id as a value */
    from(characterIds).pipe(

      /* merge each id to an Observable of the http get request */
      mergeMap(id => this.http.get(`https://swapi.co/api/people/${id}`)),

      /* cancel any pending requests when the component unloads.
        this will avoid any RxJS memory leaks */
      takeUntil(this.endSubs$)
    ).subscribe(
      character => {
        /* note that you will only receive 1 character at a time */
        console.log('received character', character);
        this.loadedCharacter[character.id] = character; // or whatever you want to do
      },
      err => console.log('Error loading a character', err),
      () => console.log('All character requests have finished')
    );
  }

  /* clean up our subscriptions when the component destroys */
  ngOnDestory() {
    this.endSubs$.next();
    this.endSubs$.complete();
  }
}

РЕДАКТИРОВАТЬ: Я добавил некоторый код очистки Rx JS, чтобы избежать утечек памяти из mergeMap , Любые запросы, ожидающие завершения загрузки этого компонента, будут отменены. Вот пример ответа SO , объясняющего наблюдаемую очистку, и здесь есть соответствующая статья Rx JS о том, где разместить takeUntil().

1 голос
/ 07 апреля 2020

Вы можете извлечь логи c для создания наблюдаемой внутри общей функции и использовать ее, как показано ниже:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  loadedCharacter: {};
  constructor(private http: HttpClient) {}

  ngOnInit() {
    let character1 = this.createHttpObservable('1');
    let character2 = this.createHttpObservable('2');

    forkJoin([character, character2]).subscribe(results => {
      // results[0] is our character
      // results[1] is our character2
    });
  }

 createHttpObservable(id:string) {
   const url = 'https://swapi.co/api/people/';
   return this.http.get(`url${id}`);
 }
}
...