Angular параллельные и последовательные запросы на RxJS

Допустим имеется задача выполнить 3 параллельных запроса, и на основе их результата выполнить четвёртый запрос.

forkJoin - параллельные запросы

forkJoin - это аналог поведения Promise.all на RxJS Observables.

Ожидает пока все переданные Observables завершатся, а затем объединяет в массив последние значения, которые они выкидывают.

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

// параллельно

forkJoin(
  this._requestService.makeRequest1(),
  this._requestService.makeRequest2(),
)
.subscribe(([res1, res2]) => {
    this.propOne = res1;
    this.propTwo = res2;
});    

mergeMap - последовательные запросы

mergeMap совмещает пришедший поток и запускаемый поток. Элементы пришедшего потока порождают новый поток. Этот оператор избавляет от подписки в подписке.

import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

const source = of('Hello');
const example = source.pipe(mergeMap(val => of(`${val} World!`)));
example.subscribe(console.log); // выведет: 'Hello World!'

Применительно к запросом

// последовательно

this._requestService.makeRequest1().pipe(
  mergeMap((res1) => this._requestService.makeRequest2(res1)),
),
.subscribe(res2 => {
    this.propTwo = res2;
});

Пример

Возвращаясь к задаче.

import { Component, Injectable, OnInit } from '@angular/core';
import { forkJoin, of } from 'rxjs';
import { delay, mergeMap, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class RequestService {
  makeRequest(value: string, delayDuration: number) {
    // симуляция http запроса
    return of(`${value} завершён`).pipe(
      delay(delayDuration)
    );
  }
  makeAnotherRequest(...args) {
    // симуляция http запроса
    return of(args.join()).pipe(
      delay(1000)
    );
  }  
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h1>forkJoin + mergeMap</h1>    
      <ul>
        <li>{{ propOne }}</li>
        <li>{{ propTwo }}</li>
        <li>{{ propThree }}</li>
        <li>{{ propFour }}</li>
      </ul>
    </div>
  `,
})
export class AppComponent implements OnInit  {
  public propOne: string;
  public propTwo: string;
  public propThree: string;
  public propFour: string;
  constructor(private _requestService: RequestService) {}

  ngOnInit() {
    // симуляция 3 запросов с разным временем ответа
    forkJoin(
      this._requestService.makeRequest('Запрос 1', 1500),
      this._requestService.makeRequest('Запрос 2', 500),
      this._requestService.makeRequest('Запрос 3', 2500)
    )
    .pipe(
      tap(([res1, res2, res3]) => {
        this.propOne = res1;
        this.propTwo = res2;
        this.propThree = res3;
      }),
      mergeMap(result => this._requestService.makeAnotherRequest(result))
    )
    .subscribe(res4 => {
      this.propFour = res4;
    });
  }
}

Посмотреть пример на Stackblitz


Похожие записи

@Directive v/s @Component in Angular

Компоненты создают DOM элементы и добавляют к ним поведение, а директивы только добавляют поведение к существующим DOM элементам

13 августа 2018 г. в Angular

Angular setter

Пример задания значения булева Input свойства как директивы, на примере:

09 октября 2018 г. в Angular

Angular. Редирект по условию

Пример условного перенаправления пользователя в зависимости от некого количества

  • 0 - dashboard
  • 1 - карточка
  • 2 и более - список
10 января 2019 г. в Angular