具有相同请求的多个API调用 [英] Multiple API calls with same request
问题描述
我想使用相同的端点通过不同的ID进行多个HTTP调用.有没有更好的方法可以从UI处理此问题.我们现在无法更改后端,有更好的方法吗?
I want to make multiple HTTP calls with the same endpoint passing different id. Is there a better way to handle this from UI. We cannot change the backend right now, is there a better way?
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个选项:
-
您是否可以使用
forkJoin()
将所有可观察对象组合成一个数组
Is the option you have where you use
forkJoin()
to combine all the observables into an array
- PROS :您知道您将在
subscribe()
中加载所有数据 - 缺点:,您必须等待每个 HTTP请求完成,然后
forkJoin
发出该值- 注意:您可以实现一个不错的帮助程序功能,例如@Prince建议
- PROS: you know you will have all your data loaded inside you
subscribe()
- CONS: you have to wait for every HTTP request to finish before
forkJoin
emits the value- Note: you can implement a nice helper function like @Prince recommended
您可以使用
mergeMap()
您的ID并在一个可观察对象完成时做出反应You can use
mergeMap()
for your IDs and react whenever one of the observables completes- PROS :您不必等待每个 HTTP请求完成.您可以在完成后对它们进行反应.此外,您可以更轻松地处理错误(因此,如果一个请求失败,您仍然可以继续处理其他请求).
- 缺点:,您必须稍微不同地处理
.subscribe()
中的发射值
- PROS: you don't have to wait for every HTTP request to complete. You can react as they complete. Also, you can handle errors easier (so if one request fails you can still continue with the other requests).
- CONS: you have to handle your emitted values in the
.subscribe()
a little differently
最终,您将需要确定哪种方法最适合您.您的实现没有任何问题.我注意到您将
loadedCharacter
保留为对象,因此,老实说,选项2可能对您的用例有用At the end of the day, you will need to decided which approach is best for you. There isn't anything wrong with the implementation you have. I noticed you are keeping your
loadedCharacter
as an object, so honestly option 2 may be good for your use case选项2 的示例代码.参见 stackblitz 以获得一个小型演示:
Example code for Option 2. See this stackblitz for a small demo:
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清理代码,以避免
mergeMap
引起的任何内存泄漏.卸载此组件时,任何待处理的请求都将被取消.此处是一个示例SO答案,解释了可观察的清理,并I added some RxJS cleanup code to avoid any memory leaks from the
mergeMap
. Any requests that are pending when this component unloads will be cancelled. Here is an example SO answer explaining Observable cleanup, and here is a relevant RxJS article on where to place yourtakeUntil()
.这篇关于具有相同请求的多个API调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!