How to handle/queue multiple same http requests wi

2020-06-22 13:15发布

问题:

I am making an Angular 4 app. Components are subscribing Observable. Sometimes Observable call the same url. For example 'refresh Access Token' if needed before any http request. But if I make different 3 http requests, it will "refresh if needed" 3 times the refresh token.

So how to make only one http get to get a refreshed access token, and make the other observables 'wait' for the first one ? (I know 'wait' is not the good word for Observables).

        public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
            return this.getAccessToken().mergeMap(accessToken => {
              return this.http.get(url, options);
            });
          }

// And

this.get('www.myapi.com/one').subscribe(data=>console.log('one',data))
this.get('www.myapi.com/two').subscribe(data=>console.log('two',data))
this.get('www.myapi.com/three').subscribe(data=>console.log('three,data))

回答1:

It seems like you can use the share() operator that makes sure there's always only one subscription to the source Observable.

However this will require you to restructure your code because all observers need to use the same instance of share():

const sharedToken = this.getAccessToken().share();

public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
  return sharedToken.mergeMap(accessToken => {
    return this.http.get(url, options);
  });
}


回答2:

Use an operator called forkJoin. If you are familiar with Promises this is very similar to Promise.all(). The forkJoin() operator allows us take a list of Observables and execute them in parallel. Once every Observable in the list emits a value the forkJoin with emit a single Observable value containing a list of all the resolved values from the Observables in the list

please go through the below example:

Import:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';

Let assume you have to get three pages

var pages:number[] = [1, 2, 3];

Or var pages:number[]=new Array(10).fill().map((v,i)=>i+1);

and then map them into an array of observables and forkJoin

Observable.forkJoin(
   pages.map(
      i => this.http.get('www.myapi.com/' + i)
        .map(res => res.json())
   )
).subscribe(people => this.people = people);

Please go Stack or forkJoin for more info.