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


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

RxJS Pipeable Operators

Начиная с версии rxjs 5.5 операторы вместо цепочки вызовов применяются как параметры функции pipe.

ngx translate attribute

Используется конструкция

<img src="image.jpg" [alt]="'KEY' | translate"> 
20 августа 2018 г. в Angular

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

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

Вставить <script> в Angular компонент

Добавление сторонних скриптов в Angular по запросу. Как известно, добавить скрипт через шаблон невозможно. Представлено решение как это сделать программно.