Angular发出多个http请求,但等待每个请求完成后再发出新请求

时间:2018-12-12 07:27:43

标签: javascript angular typescript angular-http

在angular应用程序中,我有一个包含url属性的文字对象数组。 我需要对每个对象都发出一个http请求,但是要一个接一个。

示例:

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

(这是一个示例,它们可能是更多的对象,但我不知道有多少个对象)

现在,我想向第一个URL发出请求,当我们收到响应时(或无所谓,则无所谓),然后我向第二个URL发出请求。如何有效地实现该请求?

我不想一次发出这些请求-每个请求都只能在上一次成功或失败之后进行。

6 个答案:

答案 0 :(得分:1)

使用rxJs中的 concatAll()方法,该方法收集可观察对象并在上一个完成时订阅下一个。 (或者您可以一次使用 forkJoin 进行多个请求。)

forkJoin -这将对您的所有请求进行分组并一个接一个地执行。 forkJoin 等待每个http请求完成,并将每个http调用返回的所有可观察对象分组为单个可观察数组,最后返回该可观察数组。

它接受数组作为参数。例如-

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

对于参考-https://medium.com/@swarnakishore/performing-multiple-http-requests-in-angular-4-5-with-forkjoin-74f3ac166d61

  

当您有一组可观察对象并且仅在乎每个对象的最终发射值时,最好使用此运算符。

通过另一种方式,您可以在上一个请求的错误或成功块中调用每个请求,这是一个漫长的过程。

答案 1 :(得分:0)

用户forkJoin Fork Join

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

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

forkJoin(arr);

答案 2 :(得分:0)

您可以将观测值与flatMap结合使用。由于您具有一个可观察变量列表(或要转换为可观察变量的URL列表),因此可以使用reduce

示例:

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

答案 3 :(得分:0)

可能的解决方案是使用 concatMap toArray switchMapTo

所以首先您有一个URL列表:

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

然后将它们转换为可观察的:

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()

答案 4 :(得分:0)

使用 concatMap,确保使用 catchError,因为如果一个链接产生错误,您不希望整个链都失败。

StackBlitz

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

答案 5 :(得分:-1)

为此,我们可以使用棘手的方法。您必须在如下所示的服务中创建方法。

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

在组件中,您必须按以下方式调用此方法。

//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]);
}
  }
  );
}