繁体   English   中英

具有相同请求的多个 API 调用

[英]Multiple API calls with same request

我想使用传递不同 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
    });
  }
}

您可以提取逻辑以在常见的 function 中创建可观察对象,并像下面这样使用它:

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}`);
 }
}

基本上有2个选项:

  1. 是您使用forkJoin()将所有可观察对象组合成一个数组的选项吗

    • 优点:您知道您将在subscribe()中加载所有数据
    • 缺点:您必须等待每个HTTP 请求在forkJoin发出值之前完成
      • 注意:您可以像@Prince 推荐的那样实现一个很好的助手 function
  2. 您可以使用mergeMap()作为您的 ID,并在其中一个可观察对象完成时做出反应

    • 优点:您不必等待每个HTTP 请求完成。 你可以在他们完成时做出反应。 此外,您可以更轻松地处理错误(因此,如果一个请求失败,您仍然可以继续处理其他请求)。
    • 缺点:你必须在.subscribe()中处理你发出的值有点不同

归根结底,您需要决定哪种方法最适合您。 您的实施没有任何问题。 我注意到您将loadedCharacter保留为object,所以老实说选项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();
  }
}

编辑:我添加了一些 RxJS 清理代码以避免任何 memory 从mergeMap泄漏。 当此组件卸载时,任何挂起的请求都将被取消。 这是一个解释 Observable 清理的示例 SO 答案这里是有关放置takeUntil()的位置的相关 RxJS 文章。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM