同一请求的多个 API 调用

Tha*_*thy 2 javascript rxjs angular

我想使用传递不同 id 的同一端点进行多个 HTTP 调用。有没有更好的方法从 UI 处理这个问题。目前无法更改后端,有更好的方法吗?

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
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

Jas*_*ngh 5

您可以提取逻辑以在公共函数内创建可观察的内容并按如下所示使用它:

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}`);
 }
}
Run Code Online (Sandbox Code Playgroud)


DJ *_*use 5

基本上有两种选择:

  1. 是您用来forkJoin()将所有可观察量组合到数组中的选项

    • 优点:您知道所有数据都会加载到您体内subscribe()
    • 缺点:您必须等待每个HTTP 请求完成才能forkJoin发出值
    • 注意:你可以实现一个很好的辅助函数,比如@Prince推荐的
  2. 您可以使用mergeMap()您的 ID 并在其中一个可观察量完成时做出反应

    • 优点:您不必等待每个HTTP 请求完成。您可以在它们完成时做出反应。此外,您可以更轻松地处理错误(因此,如果一个请求失败,您仍然可以继续处理其他请求)。
    • 缺点:你必须以.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 */
  ngOnDestroy() {
    this.endSubs$.next();
    this.endSubs$.complete();
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我添加了一些 RxJS 清理代码以避免mergeMap. 卸载此组件时任何待处理的请求都将被取消。这是一个示例 SO 答案,解释了 Observable 清理,这是一篇相关的 RxJS 文章,介绍了将takeUntil().