Flattening

You may have heard of a “flatten” function. Flatten functions take an input of some sort and “unwrap” it. (In this case, unwrapping an array is to pull out the elements in the array and use those.) This hypothetical code snippet returns [2, 4, 7, 12]:

 flatten([[2], [4, 7], 12])

Usually, a single call to flatten only unwraps by one layer. Flatten iterates through the array, unwrapping each item if possible. The element 12 cannot be unwrapped, so flatten uses the raw value in the resulting collection. Flatten can be used with more than arrays—promises and observables also can be unwrapped by passing along the data within rather than the abstraction. Promise.all is a type of flatten, taking an array of promises and returning a single promise that contains an array of all of the resulting data:

 Promise.all([
  fetch(​'/endpoint/productA'​),
  fetch(​'/endpoint/productB'​),
  fetch(​'/endpoint/productC'​)
 ])
 .then(arrayOfProducts => displayProducts(arrayOfProducts));

A common pattern is to combine a flattening function with a mapping one, called flatMap. This type of function maps and then flattens, so the name’s backward. Let’s say you had a collection of friends who all had several favorite foods. We can use flatMap to create an array of all the foods you should serve at your next party:

 let​ friends = [{
  name: ​'Jill'​,
  favoriteFoods: [​'pizza'​, ​'hummus'​]
 }, {
  name: ​'Bob'​,
  favoriteFoods: [​'ice cream'​]
 }, {
  name: ​'Alice'​,
  favoriteFoods: [​'chicken wings'​, ​'salmon'​]
 }];
 
 flatMap(friends, friend => friend.favoriteFoods);
 
 // Step 1: map
 [
  [​'pizza'​, ​'hummus'​],
  [​'ice cream'​],
  [​'chicken wings'​, ​'salmon'​]
 ]
 // Step 2: flatten (unwrapping each subarray)
 [​'pizza'​, ​'hummus'​, ​'ice cream'​, ​'chicken wings'​, ​'salmon'​]

Unwrapping an empty array results in no data being passed on. This means you can use the flatMap function as a way to filter out results you’re not interested in. Here, it’s pulling out the data where it exists, and ignoring elements that errored:

 let​ results = [
  { data: [1,2,3]},
  { error: ​'Something went wrong'​},
  { data: [7,5,7]},
  { data: [1,3,1]},
 ];
 
 let​ dataPoints = flatMap(results, result => {
 if​ (result.data) {
 return​ result.data;
  }
 return​ [];
 });
 
 console.log(dataPoints); ​// [1,2,3,7,5,7,1,3,1]

While combining several sub-arrays into a single array is commonly known as flattening, in Rx-land combining multiple observables into a single observable is called merging. Think of this like several roads all merging into a single main road. Since flatMapping combines multiple observables into a single stream, the operator is called mergeMap.

Adding mergeMap to our example means replacing map(wordString => wordString.split(/s+)) with mergeMap(wordString => wordString.split(/s+)). This results in all following operators being called many times, each with a single word. This is in contrast to regular map where each operator only receives one event (an array containing the entire content of the textbox) per keystroke. This allows control of the granularity of a stream, which will become important when we dig into inner observables in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.239.118