最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular make multiple http request but wait for each one to finish before making a new one - Stack Overflow

programmeradmin2浏览0评论

In angular app I have an array of literal objects containing a url property. I need to make a http request for each of these object, but one after another.

example:

let arr = [
    {url: ''},
    {url: ''},
    {url: ''}
]

(that is an example, they may be more of objects, and I don't know how many)

Now, I want to make a request to first url and when we have a response from it (or error, doesn't matter) THEN I want to make a request to second etc. Any idea how to efficiently implement that?

I don't want to make these request at single time - each one should be made only after previous was successful or failure.

In angular app I have an array of literal objects containing a url property. I need to make a http request for each of these object, but one after another.

example:

let arr = [
    {url: 'http://example./url1'},
    {url: 'http://example./url2'},
    {url: 'http://example./url3'}
]

(that is an example, they may be more of objects, and I don't know how many)

Now, I want to make a request to first url and when we have a response from it (or error, doesn't matter) THEN I want to make a request to second etc. Any idea how to efficiently implement that?

I don't want to make these request at single time - each one should be made only after previous was successful or failure.

Share Improve this question edited Jul 25, 2021 at 6:46 Aviad P. 32.7k15 gold badges111 silver badges126 bronze badges asked Dec 12, 2018 at 7:27 deasedease 3,07613 gold badges42 silver badges77 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 1

A possible solution would be to use concatMap, toArray and switchMapTo.

So first you have a list of urls:

let arr = [{url: 'http://example./url1'},{url: 'http://example./url2'}]

Then you transform them to an Observable:

of(arr)
.pipe(
   concatMap(r=> http.get(r.url)), //MAKE EACH REQUEST AND WAIT FOR COMPLETION
   toArray(), // COMBINE THEM TO ONE ARRAY
   switchMapTo(http.get("FINALURL") // MAKE REQUEST AFTER EVERY THING IS FINISHED
)).subscribe()

We can use tricky method for this. You have to create method in the service like below.

// TestService.ts
callUrlAsync(url): any[] {
    return this._http.get<any>(url);
  }

In the ponent you have to call this method as follows.

//ponent.ts

let arr = [{url: 'http://example./url1'},{url: 'http://example./url2'}, 
{url:'http://example./url3'}]

public i = 0;

//trigger method
testMethod(){
this.callUrl(this.arr[0]);
}

callUrl(url){
this.testService.callUrlAsync(url)
  .subscribe(data => {
    console.log(data);
      if(this.arr.length > this.i){
      this.i++;
      this.callUrl(this.arr[this.i]);
}
  }
  }, error => {
    this.Error(error);
    if(this.arr.length > this.i){
    this.i++;
    this.callUrl(this.arr[this.i]);
}
  }
  );
}

You can bine your observables with flatMap. Since you have a list of observables (or a list of urls that you want to transform into observables), you can do this with reduce.

Example:

// just some options to make a simple GET without parsing JSON
// and reading the response status
const httpOptions = {
  headers: new HttpHeaders({
    'Accept': 'text/html, application/xhtml+xml, */*',
    'Content-Type': 'application/x-www-form-urlencoded'
  }),
  responseType: 'text',
  observe: 'response'
}; 

const urls = [
  { url: 'www.google.' },
  { url: 'www.stackoverflow.' },
  { url: 'www.imgur.' },
  { url: 'www.reddit.' },
];

const reducer = (cur, acc) => acc.pipe(
  flatMap(r => cur)
);

const all$ = urls.map(({url}) => 
                    // create the get requests
                    http.get(url, httpOptions).pipe(
                      // do something with the result
                      tap(r => console.log(r.url + ': ' + r.status))
                 ))
                 .reverse()
                 .reduce(reducer);

all$.subscribe(x => {});

User forkJoin Fork Join

let arr = [{url: 'http://example./url1'},{url: 'http://example./url2'},{url: 

'http://example./url3'}]

forkJoin(arr);

Use concatAll() method from rxJs which collect observables and subscribe to next when previous pletes. (Or you can use forkJoin for multiple request at single time.)

forkJoin - This will group all your request and execute one by one. forkJoin waits for each http request to plete and group’s all the observables returned by each http call into a single observable array and finally return that observable array.

It accepts array as parameter. for example -

    let response1 = this.http.get(requestUrl1);
    let response2 = this.http.get(requestUrl2);
    let response3 = this.http.get(requestUrl3);
    return Observable.forkJoin([response1, response2, response3]);

For ref. - https://medium./@swarnakishore/performing-multiple-http-requests-in-angular-4-5-with-forkjoin-74f3ac166d61

This operator is best used when you have a group of observables and only care about the final emitted value of each.

In another way you can call each request in previous request's error or success block, which is lengthy process.

Use concatMap, make sure to catchError because you don't want the entire chain to fail if one link produced an error.

StackBlitz

let results$ = from(arr).pipe(
  concatMap(({ url }) =>
    requestData(url).pipe(catchError(err => of(`error from ${url}`)))
  )
);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论