簡體   English   中英

Angular 4 - 在迭代中處理嵌套訂閱的最佳方法是什么

[英]Angular 4 - What is the best way to handle the nested Subscriptions in Iterations

我正在嘗試處理 http 調用的訂閱嵌套在迭代中的情況。

1) 在第一個返回的 observable 中,我會得到一個 URLS 對象

2) 我需要遍歷這些 URL 並對這些 URls 進行 http 調用

3)第三步的情況相同,我將獲取網址並執行與第二步相同的操作

4)最后我從第三步得到的數據我需要推送到最終對象。

let finaldata = [];
this.service1.getstep1Data().subscribe((data1) => {
  // data1 = { name : 'abc', urls : ['http://url1.com','http://url2.com',........,'http://urlz.com']};
  data1.urls.foreach((url) => {
    this.service2.getstep2Data(url).subscribe((data2) => {
      // data2 = { name : 'abc', urls : ['http://url1.com','http://url2.com',........,'http://urlz.com']};
      data2.urls.foreach((url) => {
        this.service3.getfinalData(url).subscribe((data) => {
          // data = ["one","two"...."xyz"]
          finaldata.push(data[0]);
        })
      })
    })
  })
})

現在的問題是處理迭代中的異步調用,它不會相互等待。

我想等待所有異步調用在第二步中完成,然后執行第三步,否則我們沒有第三步的 URLS 來進行休息調用

我知道迭代異步調用不是一個好習慣。

有人可以幫助我進行最佳實踐嗎?

************ 提前致謝 *************

您可以使用forkJoin執行多個 http 請求並等待所有請求完成。 然后歸結為以正確的方式映射到連接的結果,然后提取您想要的數據。

import { of, Observable, forkJoin } from 'rxjs';
import { switchMap, concatMap, map, reduce } from 'rxjs/operators';

this.service1.getStep1Data()
  .pipe(
    // we execute multiple getSet2Data requests for each data1 and wait for each to complete
    switchMap(data1 => forkJoin(data1.urls.map(url => this.service2.getStep2Data(url)))),
    // we spread the data2 responses
    switchMap(data2s => of(...data2s)),
    // we execute multiple getfinalData requests for each data2 and emit the results in the
    // order of the data2 results
    concatMap(data2 => forkJoin(data2.urls.map(url => this.service3.getfinalData(url)))),
    // we map to the data we want from the finalData result
    map(data3perData2 => data3perData2.map(data3 => data3[0])),
    // we concatenate the results so that only one array gets emmited
    reduce((acc, data) => acc.concat(data))
  )
  .subscribe(finalData => this.doMyThing(finalData));

或者,您可以使用另一個forkJoin包裝多個forkJoin結果,而不是先傳播 data2 響應並稍后減少 Observable 。

this.service1.getStep1Data()
  .pipe(
    switchMap(data1 => forkJoin(data1.urls.map(url => this.service2.getStep2Data(url)))),
    // execute getfinalData for every url from data2 and wait for all results
    // do this for every data2 object 
    switchMap(data2s => forkJoin(data2s.map(data2 => forkJoin(data2.urls.map(url => this.service3.getfinalData(url)))))),
    // fullData will be string[][][], so we flatten that to string[] with the first elements
    // from data3
    map(fullData => [].concat(...fullData).map(data3 => data3[0]))
  )
  .subscribe(finalData => this.doMyThing(finalData));

最后的映射和減少取決於您希望最終輸出的樣子。

https://stackblitz.com/edit/angular-1ze4w4

要對服務器 RxJs 操作符(如 mergeMap)進行多次 HTTP 調用,forkJoin 將最好地處理這種情況。

以下示例示例將對您的情況有所幫助。

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { forkJoin } from "rxjs/observable/forkJoin";

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  loadedCharacter: {};
  constructor(private http: HttpClient) { }

  ngOnInit() {
    let character = this.http.get('https://swapi.co/api/people/1');
    let characterHomeworld = this.http.get('http://swapi.co/api/planets/1');

    forkJoin([character, characterHomeworld]).subscribe(results => {
      // results[0] is our character
      // results[1] is our character homeworld
      results[0].homeworld = results[1];
      this.loadedCharacter = results[0];
    });
  }
}

您可以使用 RXJS forkjoin 來實現解決方案。

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
  name = 'Angular';
  constructor(private appservice: AppService){
    this.appservice.getService1().subscribe(urls=>{
      this.appservice.getService2(urls).subscribe(finalArrayList=>{
        this.appservice.getService3(finalArrayList).subscribe();
      });
    });
  }

  ngOnInit(){

  }
}

創建 Stackblitz https://stackblitz.com/edit/angular-fkh7xr

您可以使用Subject而不是簡單的觀察者。 主題將提供間隔更新,因此將有助於 api 數據的同步使用。

堆疊閃電戰演示

this.api.subjectCreateUser1.subscribe((data1) => {
  if (data1) {
      this.api.subjectCreateUser2.subscribe((data2) => {
          if(data2) {
              this.api.subjectCreateUser3.subscribe((data3) => {
                   if (data3) {
                       console.log(data3);
                   }
              });
          }
      });
  }
});

和 api 調用如下....

return this.newHttp.post(this._baseApiUrl, this.data1)
 .subscribe(success => {
   console.log(success);
   this.subjectCreateUser1.next(success);
 }, error => {
   this.subjectCreateUser1.next(error);
});

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM