Angular 4 - Каков наилучший способ обработки вложенных подписок в итерациях - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь справиться с ситуацией, когда подписки на http-вызовы вложены в итерации.

1) В первой возвращаемой наблюдаемой я получу объект URLS

2) Мне нужноперебрать эти URL-адреса и сделать http-вызовы по этим URls

3) Тот же случай на третьем шаге, я получу URL-адреса и сделаю то же самое, что и во втором

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

Теперь проблема заключается в обработке асинхронных вызовов в итерациях, которые не будут ждать друг друга.

Я хочудождитесь завершения всех асинхронных вызовов на втором шаге, а затем выполните третий шаг, в противном случае у нас нет URL-адресов для третьего шага, чтобы сделать остальные вызовы

Я знаю, что повторение асинхронных вызовов не является хорошей практикой.

Может ли кто-нибудь помочь мне с лучшей практикой для этого.

************ Заранее спасибо *************

Ответы [ 4 ]

0 голосов
/ 06 февраля 2019

Вы можете использовать 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));

В качестве альтернативы, вместо того, чтобы сначала распространять ответы data2, а затем уменьшать Observable, вы можете обернуть несколько forkJoin результат с другим forkJoin.

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

0 голосов
/ 06 февраля 2019

Вы можете использовать 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

0 голосов
/ 06 февраля 2019

Вы можете использовать Тема вместо простого наблюдателя.Субъект будет предоставлять интервальные обновления, поэтому будет полезен для синхронизированного использования данных API.

демонстрация stackblitz

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

Надеюсь, это поможет.

0 голосов
/ 06 февраля 2019

Чтобы сделать несколько HTTP-вызовов на серверный оператор RxJs, такой как mergeMap, 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];
    });
  }
}
...