sainture
3/13/2018 - 6:11 AM

concatMap

// Scenario
// Most APIs provide endpoints for retrieving whole collections of items with single request.

// Unfortunately, sometimes we will end up in situation where we have to consume 3rd party API
// which doesn’t provide such convenience.

// Hacker News API is an example of API which doesn’t let us retrieve collection of items in a single request.
// Instead, what we get is a list of IDs and we have to retrieve corresponding items one by one

// concatMap() solution

// Retrieving collection of items with a known set of IDs can be performed using RxJS from() method which 
// passes our IDs one by one to the following operators.

// In our case we want to perform a HTTP request for every ID and Angular HttpClient returns observable of 
// a response by default. This leaves us with observable of observables but we’re much more interested
// in the actual responses instead

// To solve this situation we have to flatten our observable stream and one of the available operators is
// concatMap() which does exactly what we need

from(ids).pipe(
     concatMap(id => this.httpClient.get(`item/${id}`))
);

// concatMap() flattens our stream from observable of observables to observable of responses

// Another important property is that it will wait for completion of previous observable before executing
// next one. This translates into every request waiting for completion of previous one which might not 
// be exactly the best for performance.

// another example

const source = of(2000, 1000);
// map value from source into inner observable, when complete emit result and move to next
const example = source.pipe(
  concatMap(val => of(`Delayed by: ${val}ms`).pipe(delay(val)))
);
//output: With concatMap: Delayed by: 2000ms, With concatMap: Delayed by: 1000ms
const subscribe = example.subscribe(val =>
  console.log(`With concatMap: ${val}`)
);


/*
concatMap does not subscribe to the next observable until the previous completes, the value from the source 
delayed by 2000ms will be emitted first. Contrast this with mergeMap which subscribes immediately to inner
observables, the observable with the lesser delay (1000ms) will emit, followed by the observable which takes
2000ms to complete
*/