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


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

Angular dependency injection

Определение Provider (useClass, useValue, useFactory ), Injector. Декоратор @Inject, ключ multi: true

13 ноября 2018 г. в Angular

HTML атрибуты и DOM свойства

  • Значение HTML атрибута указывает начальное значение;
  • Значение DOM свойства является текущим значением;
  • Атрибуты инициализируют DOM свойства.

Не ставить фокус по клику

Проблема заключалась в следующем: когда имеется интерактивный элемент с :focus стилем и вы щелкаете по этому элементу, на нём остаётся focus стиль (outline обводка). У нативной кнопки всё работает as expected, но стоит её добавить любой стиль и, как побочный эффект, меняется её поведение.

Angular. Functions & getters в шаблонах

На каждый цикл механизма обнаружения изменений выполняется метод из шаблона. Если этого надо избежать, то следует использовать pure pipe или результат выполнения присвоить свойству компонента