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

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

Переиспользуемые анимации в Angular

Для создания анимации используется функция animation(). Для её использования — useAnimation(). Приводится пример переиспользуемой анимации, а также создание анимации через литерал объекта.

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

TypeScript Enum Flags (bitmask)

enum FileAccess {
    None,             // 000
    Read    = 1 << 1, // 001
    Write   = 1 << 2, // 010
    Execute = 1 << 3, // 100
    ReadWrite  = Read | Write, // 011
}

const f = FileAccess.Read | FileAccess.Execute;
f & FileAccess.Execute // true