简体   繁体   English

Angular 发出多个 http 请求,但在发出新请求之前等待每个请求完成

[英]Angular make multiple http request but wait for each one to finish before making a new one

In angular app I have an array of literal objects containing a url property.在 angular 应用程序中,我有一个包含 url 属性的文字对象数组。 I need to make a http request for each of these object, but one after another.我需要为这些对象中的每一个发出 http 请求,但一个接一个。

example:例子:

let arr = [
    {url: 'http://example.com/url1'},
    {url: 'http://example.com/url2'},
    {url: 'http://example.com/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?现在,我想向第一个 url 发出请求,当我们收到它的响应(或错误,无关紧要)然后我想向第二个等发出请求。知道如何有效地实现它吗?

I don't want to make these request at single time - each one should be made only after previous was successful or failure.我不想一次性提出这些请求 - 每个请求都应该在前一个成功或失败之后提出。

You can combine your observables with flatMap .您可以将 observable 与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 .由于您有一个 observables 列表(或您想要转换为 observables 的 url 列表),您可以使用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.com' },
  { url: 'www.stackoverflow.com' },
  { url: 'www.imgur.com' },
  { url: 'www.reddit.com' },
];

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 => {});

A possible solution would be to use concatMap , toArray and switchMapTo .一个可能的解决方案是使用concatMaptoArrayswitchMapTo

So first you have a list of urls:所以首先你有一个 url 列表:

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

Then you transform them to an Observable:然后将它们转换为 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()

Use concatMap , make sure to catchError because you don't want the entire chain to fail if one link produced an error.使用concatMap ,确保catchError因为如果一个链接产生错误,你不希望整个链失败。

StackBlitz 闪电战

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

User forkJoin Fork Join用户forkJoin Fork Join

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

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

forkJoin(arr);

Use concatAll() method from rxJs which collect observables and subscribe to next when previous completes.使用来自 rxJs 的concatAll()方法,该方法收集可观察对象并在上一个完成时订阅下一个。 (Or you can use forkJoin for multiple request at single time.) (或者您可以一次使用forkJoin进行多个请求。)

forkJoin - This will group all your request and execute one by one. forkJoin - 这将对您的所有请求进行分组并一一执行。 forkJoin waits for each http request to complete and group's all the observables returned by each http call into a single observable array and finally return that observable array. forkJoin等待每个 http 请求完成,并将每个 http 调用返回的所有 observable 分组到一个observable 数组中,最后返回该 observable 数组。

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.com/@swarnakishore/performing-multiple-http-requests-in-angular-4-5-with-forkjoin-74f3ac166d61 - https://medium.com/@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.当您有一组 observable 并且只关心每个的最终发出值时,最好使用此运算符。

In another way you can call each request in previous request's error or success block, which is lengthy process.在另一种方式中,您可以调用前一个请求的错误或成功块中的每个请求,这是一个漫长的过程。

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 component you have to call this method as follows.在组件中,您必须按如下方式调用此方法。

//component.ts

let arr = [{url: 'http://example.com/url1'},{url: 'http://example.com/url2'}, 
{url:'http://example.com/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]);
}
  }
  );
}

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

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